
比较两种架构的文章已经很多了,我不再赘述。
以一个简单的登录操作为例:
先说View
public interface BaseInterface {
/**
* 显示请求中dialog
*/
public void showDownloadingDialog();
/**
* 隐藏请求中dialog
*/
public void dismissDownloadingDialog();
/**
* 网络错误
*/
public void showInternetError();
}
上面定义了凡是具有网络请求的界面都必备的方法。
下面是LoginActivity所特有的一些操作。
public interface ILoginView extends BaseInterface {
/**
* 登录成功后干啥
*/
public void loginSuccess();
/**
* 登录失败后干啥
*/
public void loginFailed();
/**
* 返回账号
*/
public String getAccount();
/**
* 返回密码
*/
public String getPsw();
}
接下来是LoginActivity的具体实现。
public class LoginView extends BaseActivity implements ILoginView {
ILoginPresenter iLoginPresenter = null;
@Bind(R.id.etAccount)
EditText etAccount;
@Bind(R.id.etPsw)
EditText etPsw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
subSetContentView(R.layout.activity_login);
iLoginPresenter = new LoginPresenter(this);
}
@Override
public void loginSuccess() {
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
}
@Override
public String getAccount() {
return etAccount.getText().toString().trim();
}
@Override
public String getPsw() {
return etPsw.getText().toString().trim();
}
@Override
public void loginFailed() {
Toast.makeText(this, "账号或密码错误", Toast.LENGTH_SHORT).show();
}
@OnClick({R.id.btnLogin})
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.btnLogin:
iLoginPresenter.login();
break;
}
}
细心的你也许会想,BaseInterface接口里面的三个方法去哪实现了呢,答案在BaseActivity里。
public class BaseActivity extends Activity implements OnClickListener {
//略去其他代码
public void showDownloadingDialog() {
Toast.makeText(this, "showDownloadingDialog ...", Toast.LENGTH_SHORT)
.show();
}
public void dismissDownloadingDialog() {
Toast.makeText(this, "dismissDownloadingDialog ...", Toast.LENGTH_SHORT)
.show();
}
public void showInternetError() {
Toast.makeText(this, "网络错误", Toast.LENGTH_SHORT).show();
}
}
接下来说Presenter
public interface ILoginPresenter {
public void login();
}
public class LoginPresenter implements ILoginPresenter {
private ILoginView iLoginView = null;
private LoginModel loginModel = null;
public LoginPresenter(ILoginView iLoginView) {
this.iLoginView = iLoginView;
this.loginModel = new LoginModel();
}
@Override
public void login() {
String account = iLoginView.getAccount();
String psw = iLoginView.getPsw();
iLoginView.showDownloadingDialog();
// 1.模拟本地登录
boolean ifSuccess = loginModel.loginLocal(account, psw);
if (ifSuccess) {
iLoginView.loginSuccess();
} else {
iLoginView.loginFailed();
}
// 2.模拟网络登录
loginModel.loginInternet(account, psw, new OnLoginListener() {
@Override
public void loginSuccess() {
iLoginView.dismissDownloadingDialog();
iLoginView.loginSuccess();
}
@Override
public void loginFailed() {
iLoginView.dismissDownloadingDialog();
iLoginView.loginFailed();
}
@Override
public void internetError() {
iLoginView.dismissDownloadingDialog();
iLoginView.showInternetError();
}
});
}
/**
* 用于获取用户登录结果的回调
*/
public interface OnLoginListener {
void loginSuccess();
void loginFailed();
void internetError();
}
}
最后说Model
public class LoginModel {
/**
* 通过查询本地数据库验证用户名密码是否正确,未开启子线程
*/
public boolean loginLocal(String account, String psw) {
String temp = "1";
if (temp.equals(account) && temp.equals(psw)) {
return true;
} else {
return false;
}
}
/**
* 通过网络,向服务器验证用户名密码是否合法,需要传入回调
*/
public void loginInternet(String account, String psw,
LoginPresenter.OnLoginListener onLoginListener) {
// do some internet thing
// if success,invoke onLoginListener.loginSuccess() and maybe need to store necessary data to local DB;
// if failed,invoke onLoginListener.loginFailed();
// if internet error,invoke onLoginListener.internetError();
}
}
好像忘记介绍activity布局了,很简单
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<EditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="账号" />
<EditText
android:id="@+id/etPsw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码" />
<Button
android:id="@+id/btnLogin"
style="@style/btn_universal"
android:text="登录" />
</LinearLayout>
效果就是酱婶儿的

一点体会
Activity代码是不是清爽了很多,因为业务逻辑都被剥离出去了。
什么是接口?接口就是“协议”啊。业务逻辑通常是代表了一系列或繁或简的操作,如果全部在View里面实现,会搞得代码非常难以维护,这显然是不合理的。所以,在MVP中,View只定义了这一系列操作的开端,例如,点击了登录按钮,具体业务是在presenter中实现的。可以这样做的前提是,View与Presenter之间已经签订了协议——“你需要我干什么,按照协议里商量的好的办法告诉我就行了”。
网友评论