Xcode 提高效率的快捷键

CTRL + O 新行

CTRL + N 下一行

CTRL + P 上一行

CTRL + A 行首

CTRL + E 行尾

CTRL + F 向前

CTRL + Option + F 向前(按单词)

CTRL + B 向后

CTRL + Option + B 向后(按单词)

CTRL + H 删除光标前一字符

CTRL + D 删除光标后一字符

DOMContentLoaded事件

过去,当一个页面完成加载时,初始化脚本的方法是使用load事件,但这个类函数的缺点是仅在所有资源都完全加载后才被触发,这有时会导致比较严重的延迟,开发人员随后创建了一种自定义事件,domready,它在DOM加载之后及资源加载之前被触发.
domready事件迅速被众多JavaScript库所采用,它开始在本地浏览器中以DOMContentLoaded的形式被使用;此外,它目前已在HTML5中被标准化,下面的代码显示了DOMContentLoaded是如何在document对象中被触发的;
document.addeventListener(‘DOMContentLoaded’,function(){…},false);
值得注意的是,这个网站的行为层可以被更快速地启动,这意味着用户可以更快开始浏览网站,这对于连接速度慢的网络或者包含大量图片并需要一些时间加载图片的网页来说特别重要,如果只想在所有资源都完成加载之后运行脚本, 那么仍然可以使用load.

koa2.0.0 webpack 结合 动态调试代码

koa2.0.0 的路由和视图渲染完之后的一个问题就是,如何高效的开发前端代码。

因为我之前的前端代码是用webpack进行打包,然后打包过程中,使用babel实现了,ES6语法的转换,这行我就不能太干脆的丢弃webpack,然后里面使用了react+react-router+reflux,整个开发体系还是比较可以的。为了整合之前的代码,需要将之前的connect框架改为koa2.0.0,毕竟koa的实现方式还有与express,connect等这样的框架,实现方式不太一样,所以,稍微还有有点小困难,不过我这里记录下,也就不困难了。

从webpack-dev-server说起,我们使用webpack-dev-server是为了能够时时监控我们的代码改变,然后用它自己的socket-io去刷新我们的页面,实现了代码修改即页面重载,当然只是在开发环境。

webpack-dev-server并没有多大的改变,只是将原来的一个proxy的操作去掉了,然后整合到koa的启动文件里面了。

const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const config = require('./webpack.config.development');
const debug = require('debug');
new WebpackDevServer(webpack(config), {
  publicPath: config.output.publicPath,
  hot: true,
  noInfo: false,
  historyApiFallback: true,
  stats: { colors: true },
  headers: { 'Access-Control-Allow-Origin': '*' }
}).listen(8080, '127.0.0.1', function(err,result) {
  if (err) {
    console.log(err);
  }
  console.log('Webpack Listening at 127.0.0.1:8080');
});

关于webpack的config文件的代码是不需要改变的,继续使用。

下面就是在koa的启动文件里面加入启动需要的proxy处理。

//解析 开发环境 development
app.use(convert(proxy({
  host:'http://127.0.0.1:8080/js',
  match: /^\/js\//
})));

就这么简单,这里使用了两个中间件:

koa-proxy,koa-convert。

解释一下好了,就是将访问的path中有带/js/部分的路径,进行重新proxy一下就好,这样就将文件转向到了webpack-dev-server这边的对应的文件了。相关的其他的问题可以参考我之前的几篇文章

ubuntu上安装淘宝的开源Web服务器Tengine

Tengine官网:http://tengine.taobao.org/
一、什么是Tengine
Tengine 是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大 型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。
从2011年12月开始,Tengine成为一个开源项目。现在,它由Tengine团队开发和维护。Tengine团队的核心成员来自于淘宝、搜狗等互联网企业。
二、特性
继承Nginx-1.2.5的所有特性,100%兼容Nginx的配置;
动态模块加载(DSO)支持。加入一个模块不再需要重新编译整个Tengine;
输入过滤器机制支持。通过使用这种机制Web应用防火墙的编写更为方便;
动态脚本语言Lua支持。扩展功能非常高效简单;
支持管道(pipe)和syslog(本地和远端)形式的日志以及日志抽样;
组合多个CSS、JavaScript文件的访问请求变成一个请求;
可以对后端的服务器进行主动健康检查,根据服务器状态自动上线下线;
自动根据CPU数目设置进程个数和绑定CPU亲缘性;
监控系统的负载和资源占用从而对系统进行保护;
显示对运维人员更友好的出错信息,便于定位出错机器;
更强大的防攻击(访问速度限制)模块;
更方便的命令行参数,如列出编译的模块列表、支持的指令等;
可以根据访问文件类型设置过期时间;

 

三、ubuntu下安装Tengine
1、下载:
http://tengine.taobao.org/download/tengine-1.4.2.tar.gz
2、解压:

代码:
tar -xvf tengine-1.4.2.tar.gz

3、安装依赖:

代码:
sudo apt-get install libpcre++-dev libssl-dev zlib1g-dev

注:pcre依赖是rewrite模块必选;ssl是https访问的模块;zlib是启用网页gzip压缩用,必选。
4、编译安装:

代码:
cd tengine-1.4.2
./configure –prefix=/usr –conf-path=/etc/nginx/nginx.conf –pid-path=/var/run/nginx.pid –lock-path=/var/lock/nginx.lock –http-client-body-temp-path=/var/tmp/nginx/client –http-proxy-temp-path=/var/tmp/nginx/proxy –http-fastcgi-temp-path=/var/tmp/nginx/fastcgi –http-scgi-temp-path=/var/tmp/nginx/scgi –http-uwsgi-temp-path=/var/tmp/nginx/uwsgi
make
sudo make install
mkdir /var/tmp/nginx

注:没有直接使用默认配置,按照ubuntu下apt-get安装nginx的规范来配置的。
另:如果无法make,则需要安装gcc、make包:

代码:
sudo apt-get install gcc make

5、配置文件及启动:
配置文件:/etc/nginx/nginx.conf
程序启动、停止:/usr/sbin/nginx -s {start/stop/reload}
版本信息(nginx -v):Tengine version: Tengine/1.4.2 (nginx/1.2.5)

6、附nginx的服务,可以拷贝到/etc/init.d/下,就可以直接用service nginx {start/stop/restart},还可以直接添加启动服务。

代码:
#!/bin/sh### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFOPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/nginx
NAME=nginx
DESC=nginx

# Include nginx defaults if available
if [ -f /etc/default/nginx ]; then
. /etc/default/nginx
fi

test -x $DAEMON || exit 0

set -e

. /lib/lsb/init-functions

test_nginx_config() {
if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1; then
return 0
else
$DAEMON -t $DAEMON_OPTS
return $?
fi
}

case “$1” in
start)
echo -n “Starting $DESC: ”
test_nginx_config
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n “$ULIMIT” ]; then
# Set the ulimits
ulimit $ULIMIT
fi
start-stop-daemon –start –quiet –pidfile /var/run/$NAME.pid \
–exec $DAEMON — $DAEMON_OPTS || true
echo “$NAME.”
;;

stop)
echo -n “Stopping $DESC: ”
start-stop-daemon –stop –quiet –pidfile /var/run/$NAME.pid \
–exec $DAEMON || true
echo “$NAME.”
;;

restart|force-reload)
echo -n “Restarting $DESC: ”
start-stop-daemon –stop –quiet –pidfile \
/var/run/$NAME.pid –exec $DAEMON || true
sleep 1
test_nginx_config
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n “$ULIMIT” ]; then
# Set the ulimits
ulimit $ULIMIT
fi
start-stop-daemon –start –quiet –pidfile \
/var/run/$NAME.pid –exec $DAEMON — $DAEMON_OPTS || true
echo “$NAME.”
;;

reload)
echo -n “Reloading $DESC configuration: ”
test_nginx_config
start-stop-daemon –stop –signal HUP –quiet –pidfile /var/run/$NAME.pid \
–exec $DAEMON || true
echo “$NAME.”
;;

configtest|testconfig)
echo -n “Testing $DESC configuration: ”
if test_nginx_config; then
echo “$NAME.”
else
exit $?
fi
;;

status)
status_of_proc -p /var/run/$NAME.pid “$DAEMON” nginx && exit 0 || exit $?
;;
*)
echo “Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}” >&2
exit 1
;;
esac

exit 0

ReactNative 代码智能提醒(webstorm)

ReactNative 代码智能提醒 (Webstrom live template)

git clone https://github.com/virtoolswebplayer/ReactNative-LiveTemplate

说明

ReactNative的代码模板,包括:

  1. 组件名称
  2. Api 名称
  3. 所有StyleSheets属性
  4. React组件

安装

方法一

file -> import settings -> ReactNative.jar

方法二

Mac下安装

ReactNative.xml复制到 ~/Library/Preferences/WebStorm11/templates
重启 WebStrom

使用方法

通用方法

直接输入组件Api 名称的首字母, 比如想要 View ,只要输入 V自动提示代码里就会看到 View

STYLESHEET属性提示

首先 按下 command + J , 然后输入属性名的 首字母

如: 输入 f ,会自动提示 fontSize,fontFamily,fontStyle…等等

在react-native中加入socket.io

想要在react-native框架中实现长链接就得用上socket,react-native自带了一个webSocket,使用方法很简单,我们服务器端使用的是koa框架,配上socket.io简直叼炸天,网上也查过一些资料,都说到socket.io是支持webSocket的,于是乎我就兴高采烈地在react-native上写上了webSocket连接后端的代码,但是一运行。。。尼玛,报错啊,大致的意思就是连不上服务器啊,然后我就用egret引擎中的webSocket在web上也实现了一个客户端,结果也是无法连接。。。太坑爹啊。继续查资料,发现socket.io不支持ws协议。。。好吧,那么我们就在react-native上也使用socket.io吧,这会没问题了吧。

首先安装socket.io,因为react-native作为客户端,所以只要socket.io-client就行了。

执行安装命令:

npm install socket.io-client --save

然后写上代码:

import io from "socket.io-client/socket.io";
// 初始化socket
socket = io('http://77.100.10.19:3001', {jsonp: false});
// 发送消息
socket.emit("test", {"hello": "world"});
// 接收消息
socket.on('test', function (data) {
    console.log("收到消息:", data);
});

嗯,react-native客户端红屏报错了,报错的地方是node_modules\socket.io-client\socket.io.js的2985行,原因是socket.io都是用在web上的,而在移动端上navigator.userAgent是个null,那么改一下代码:

// var isAndroid = navigator.userAgent.match(/Android/i);
var isAndroid = /Android/i.test(navigator.userAgent);

然后reloadJS运行一下,嘿,没问题了,能收发消息。。。

win上搭建react-native android环境

  1. 安装JDK

既然是android开发,那么java肯定逃不掉了。从Java官网下载安装包吧。我的电脑是64位的,所以我选择下载64位的安装包。

  1. 安装Android SDK

先下载Android Studio,如果翻墙不方便的话,可以从AndroidDevTools上下载,我是翻墙从官网下载的。安装过程中会提示选择SDK的目录,默认是在系统盘,我选择的是F/android/sdk。安装完成后,先要配置一下sdk Manager的网络设置,否则在不翻墙的情况下安装sdk会很慢很慢。腾讯Bugly的镜像就挺好的,查看说明。 安装以下项目:

  • Tools/Android SDK Tools (24.4.1)
  • Tools/Android SDK Platform-tools (23.0.1)
  • Tools/Android SDK Build-tools (23.0.2)
  • Android 6.0 (API 23)/SDK Platform (1)
  • Extras/Android Support Library(23.1)

最后在系统环境变量中加入ANDROID_HOME,路径为sdk目录。

  1. 安装Git

下载Git,记得把git.exe的路径写入系统环境变量,因为在执行react-native init命名时会调用git去下载react-native的源码。

  1. 安装Node.js

官网下载最新版的安装包安装即可。npm(node package manager)是随着node.js就安装好的,为了加速安装其他的package,在cmd里输入以下命令:

npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist
  1. 安装react-native命令行工具
npm install -g react-native-cli
  1. 创建react-native android项目
react-native init MyProject

这一步要等上很长时间,原因不明。不想等待的话可以在这里下载项目文件,然后将android目录下的gradle.properties文件中的sdk.dir设为本机上sdk的目录。

sdk.dir=F:\\android\\sdk
  1. 启动react-native服务

进入项目文件夹,输入启动命令

react-native start

在浏览器中访问地址:http://localhost:8081/index.android.bundle?platform=android 第一次访问需要骚等一会,这是在生成android的bundle文件。cmd窗口别关,一直保持开启状态

  1. 安装并启动android模拟器

推荐逍遥模拟器,安装好并启动。试用了很多模拟器,有些模拟器adb无法连接,有些模拟器adb连上了,但是在却没有“摇一摇”或者菜单键,非常蛋疼。终于让我发现了逍遥模拟器,嗯,很不错。启动模拟器,在命令行中输入

adb devices

看看adb是否和设备连接上了,如果没有连接上,那么需要手动连接,连接设备需要一个端口号,那么这个端口号是多少呢?聪明的我通过查找模拟器log找到了答案。打开模拟器安装目录,然后找到MEmu\MemuHyperv VMs\MEmu\Logs下的log文件,打开此log,通过查找关键词“ port ”(注意port两边都带上空格),可以发现:

00:00:00.277099 NAT: set redirect TCP host port 21505 => guest port 21505 @ 10.0.2.15
00:00:00.278027 NAT: set redirect TCP host port 21504 => guest port 21504 @ 10.0.2.15
00:00:00.278123 NAT: set redirect TCP host port 21501 => guest port 21501 @ 10.0.2.15
00:00:00.278199 NAT: set redirect TCP host port 21500 => guest port 21500 @ 10.0.2.15
00:00:00.278274 NAT: set redirect TCP host port 21502 => guest port 21502 @ 10.0.2.15
00:00:00.278342 NAT: set redirect TCP host port 21503 => guest port 5555 @ 10.0.2.15

诶,找到了,端口号是21503,然后回到命令行,输入:

adb connect 127.0.0.1:21503

然后再一次输入

adb devices

adb是不是连上模拟器了?那么接下去就是在模拟器中运行我们的小demo了。

  1. 在模拟器中运行

进入项目目录,输入命令:

react-native run-android

第一次运行时会需要下载一些东西,等待就行。 build成功后便会在模拟器上自动运行了 react-native的hello world如果是连真机的话,很大可能看到的结果是一片白啊一片白。经查,发现是安全中心中的“悬浮窗”权限并没有对我们的这个新app开放,那么将权限开放,重启app,啊呀,一片红啊一片红。。。长按物理菜单键或者死命摇一摇手机,会弹出一个小窗口,选择“Dev Settings”,然后选择“Debug server host for device”,会弹出一个输入框,输入电脑ip地址和默认的8081端口,再次重新app,

学习 Android MVP

一、概述

对于MVP(Model View Presenter),大多数人都能说出一二:“MVC的演化版本”,“让Model和View完全解耦”等等。本篇博文仅是为了做下记录,提出一些自己的看法,和帮助大家如何针对一个Activity页面去编写针对MVP风格的代码。

对于MVP,我的内心有一个问题:

为何这个模式出来后,就能被广大的Android的程序员接受呢?

问了些程序员,他们对于MVP的普遍的认识是:“代码很清晰,不过增加了很多类”。我在第一次看到MVP的时候,看了一个demo,看完以后觉得非常nice(但是回过头来,自己想个例子写,就头疼写不出来,当然这在后文会说)。nice的原因还是因为,这个模式的确让代码的清晰度有了很大的提升。

那么,提升一般都是对比出来的,回顾下,没有应用MVP的代码结构。很多人说明显是MVC么:

  • View:对应于布局文件
  • Model:业务逻辑和实体模型
  • Controllor:对应于Activity

看起来的确像那么回事,但是细细的想想这个View对应于布局文件,其实能做的事情特别少,实际上关于该布局文件中的数据绑定的操作,事件处理的代码都在Activity中,造成了Activity既像View又像Controller(当然了Data-Binder的出现,可能会让View更像View吧)。这可能也就是为何,在该文中有一句这样的话:

Most of the modern Android applications just use View-Model architecture,everything is connected with Activity.

而当将架构改为MVP以后,Presenter的出现,将Actvity视为View层,Presenter负责完成View层与Model层的交互。现在是这样的:

  • View 对应于Activity,负责View的绘制以及与用户交互
  • Model 依然是业务逻辑和实体模型
  • Presenter 负责完成View于Model间的交互

ok,先简单了解下,文中会有例子到时候可以直观的感受下。

小总结下,也就是说,之所以让人觉得耳目一新,是因为这次的跳跃是从并不标准的MVCMVP的一个转变,减少了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理。与之对应的好处就是,耦合度更低,更方便的进行测试。借用两张图(出自:该文),代表上述的转变:

转变为:

二、MVP 与 MVC 区别

ok,上面说了一堆理论,下面我们还是需要看一看MVC与MVP的一个区别,请看下图(来自:本文):

其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的(代码中会体现)。

还有一堆概念性的东西,以及优点就略了,有兴趣自行百度。下面还是通过一些简单的需求来展示如何编写MVP的demo。

三、Simple Login Demo

效果图:

看到这样的效果,先看下完工后的项目结构:

ok,接下来开始一步一步的编写思路。

(一)Model

首先实体类User不用考虑这个肯定有,其次从效果图可以看到至少有一个业务方法login(),这两点没什么难度,我们首先完成:

package com.zhy.blogcodes.mvp.bean;

/**
 * Created by zhy on 15/6/18.
 */
public class User
{
    private String username ;
    private String password ;

    public String getUsername()
    {
        return username;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public String getPassword()
    {
        return password;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }
}


package com.zhy.blogcodes.mvp.biz;

/**
 * Created by zhy on 15/6/19.
 */
public interface IUserBiz
{
    public void login(String username, String password, OnLoginListener loginListener);
}
package com.zhy.blogcodes.mvp.biz;

import com.zhy.blogcodes.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public class UserBiz implements IUserBiz
{

    @Override
    public void login(final String username, final String password, final OnLoginListener loginListener)
    {
        //模拟子线程耗时操作
        new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(2000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                //模拟登录成功
                if ("zhy".equals(username) && "123".equals(password))
                {
                    User user = new User();
                    user.setUsername(username);
                    user.setPassword(password);
                    loginListener.loginSuccess(user);
                } else
                {
                    loginListener.loginFailed();
                }
            }
        }.start();
    }
}
package com.zhy.blogcodes.mvp.biz;

import com.zhy.blogcodes.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public interface OnLoginListener
{
    void loginSuccess(User user);

    void loginFailed();
}

实体类不用说,至于业务类,我们抽取了一个接口,一个实现类这也很常见~~login方法,一般肯定是连接服务器的,是个耗时操作,所以我们开辟了子线程,Thread.sleep(2000)模拟了耗时,由于是耗时操作,所以我们通过一个回调接口来通知登录的状态。

其实这里还是比较好写的,因为和传统写法没区别。

(二) View

上面我们说过,Presenter与View交互是通过接口。所以我们这里需要定义一个ILoginView,难点就在于应该有哪些方法,我们看一眼效果图:

可以看到我们有两个按钮,一个是login,一个是clear;

login说明了要有用户名、密码,那么对应两个方法:


    String getUserName();

    String getPassword();

再者login是个耗时操作,我们需要给用户一个友好的提示,一般就是操作ProgressBar,所以再两个:

    void showLoading();

    void hideLoading();

login当然存在登录成功与失败的处理,我们主要看成功我们是跳转Activity,而失败可能是去给个提醒:

    void toMainActivity(User user);

    void showFailedError();

ok,login这个方法我们分析完了~~还剩个clear那就简单了:

    void clearUserName();

    void clearPassword();

综上,接口完整为:

package com.zhy.blogcodes.mvp.view;

import com.zhy.blogcodes.mvp.bean.User;

/**
 * Created by zhy on 15/6/19.
 */
public interface IUserLoginView
{
    String getUserName();

    String getPassword();

    void clearUserName();

    void clearPassword();

    void showLoading();

    void hideLoading();

    void toMainActivity(User user);

    void showFailedError();

}

有了接口,实现就太好写了~~~

总结下,对于View的接口,去观察功能上的操作,然后考虑:

  • 该操作需要什么?(getUserName, getPassword)
  • 该操作的结果,对应的反馈?(toMainActivity, showFailedError)
  • 该操作过程中对应的友好的交互?(showLoading, hideLoading)

下面贴一下我们的View的实现类,哈,其实就是Activity,文章开始就说过,MVP中的View其实就是Activity。

package com.zhy.blogcodes.mvp;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.zhy.blogcodes.R;
import com.zhy.blogcodes.mvp.bean.User;
import com.zhy.blogcodes.mvp.presenter.UserLoginPresenter;
import com.zhy.blogcodes.mvp.view.IUserLoginView;

public class UserLoginActivity extends ActionBarActivity implements IUserLoginView
{


    private EditText mEtUsername, mEtPassword;
    private Button mBtnLogin, mBtnClear;
    private ProgressBar mPbLoading;

    private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_login);

        initViews();
    }

    private void initViews()
    {
        mEtUsername = (EditText) findViewById(R.id.id_et_username);
        mEtPassword = (EditText) findViewById(R.id.id_et_password);

        mBtnClear = (Button) findViewById(R.id.id_btn_clear);
        mBtnLogin = (Button) findViewById(R.id.id_btn_login);

        mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading);

        mBtnLogin.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.login();
            }
        });

        mBtnClear.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mUserLoginPresenter.clear();
            }
        });
    }


    @Override
    public String getUserName()
    {
        return mEtUsername.getText().toString();
    }

    @Override
    public String getPassword()
    {
        return mEtPassword.getText().toString();
    }

    @Override
    public void clearUserName()
    {
        mEtUsername.setText("");
    }

    @Override
    public void clearPassword()
    {
        mEtPassword.setText("");
    }

    @Override
    public void showLoading()
    {
        mPbLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading()
    {
        mPbLoading.setVisibility(View.GONE);
    }

    @Override
    public void toMainActivity(User user)
    {
        Toast.makeText(this, user.getUsername() +
                " login success , to MainActivity", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailedError()
    {
        Toast.makeText(this,
                "login failed", Toast.LENGTH_SHORT).show();
    }
}

对于在Activity中实现我们上述定义的接口,是一件很容易的事,毕竟接口引导我们去完成。

最后看我们的Presenter。

(三)Presenter

Presenter是用作Model和View之间交互的桥梁,那么应该有什么方法呢?

其实也是主要看该功能有什么操作,比如本例,两个操作:login和clear。

package com.zhy.blogcodes.mvp.presenter;

import android.os.Handler;

import com.zhy.blogcodes.mvp.bean.User;
import com.zhy.blogcodes.mvp.biz.IUserBiz;
import com.zhy.blogcodes.mvp.biz.OnLoginListener;
import com.zhy.blogcodes.mvp.biz.UserBiz;
import com.zhy.blogcodes.mvp.view.IUserLoginView;


/**
 * Created by zhy on 15/6/19.
 */
public class UserLoginPresenter
{
    private IUserBiz userBiz;
    private IUserLoginView userLoginView;
    private Handler mHandler = new Handler();

    public UserLoginPresenter(IUserLoginView userLoginView)
    {
        this.userLoginView = userLoginView;
        this.userBiz = new UserBiz();
    }

    public void login()
    {
        userLoginView.showLoading();
        userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener()
        {
            @Override
            public void loginSuccess(final User user)
            {
                //需要在UI线程执行
                mHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        userLoginView.toMainActivity(user);
                        userLoginView.hideLoading();
                    }
                });

            }

            @Override
            public void loginFailed()
            {
                //需要在UI线程执行
                mHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        userLoginView.showFailedError();
                        userLoginView.hideLoading();
                    }
                });

            }
        });
    }

    public void clear()
    {
        userLoginView.clearUserName();
        userLoginView.clearPassword();
    }



}

注意上述代码,我们的presenter完成二者的交互,那么肯定需要二者的实现类。大致就是从View中获取需要的参数,交给Model去执行业务方法,执行的过程中需要的反馈,以及结果,再让View进行做对应的显示。

ok,拿到一个例子经过上述的分解基本就能完成。以上纯属个人见解,欢迎讨论和吐槽~ have a nice day ~。

源码点击下载