Android MVP 模式深入实践探索(一),移动开发工程师简历
view
接口类中定义的基本都是一些UI
数据或者显示UI
控件的方法,然让LoginActivity
实现这个接口:
public class LoginActivity extends Activity implements ILoginView, View.OnClickListener {
private EditText mUserNameEdit;
private EditText mUserPasswordEdit;
private Button mLoginBtn;
public ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
private void initView() {
mUserNameEdit = (EditText) findViewById(R.id.edit_user_name);
mUserPasswordEdit = (EditText) findViewById(R.id.edit_user_password);
mLoginBtn = (Button) findViewById(R.id.btn_login);
mLoginBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login:
//TODO
break;
default:
break;
}
}
@Override
public String getUserName() {
return mUserNameEdit.getText().toString();
}
@Override
public String getUserPassword() {
return mUserPasswordEdit.getText().toString();
}
@Override
public void showToast(String msg) {
ToastUtils.showToast(this, msg);
}
@Override
public void onLoginSuccess() {
ToastUtils.showToast(this, "登录成功");
//跳转首页
gotoHomeActivity();
finish();
}
@Override
public void onLoginFail() {
ToastUtils.showToast(this, "登录失败");
}
@Override
public void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = DialogUtils.showSpinningProgressDialog(this, "正在登录中...", false);
} else {
if (!mProgressDialog.isShowing()) {
mProgressDialog.show();
}
}
}
@Override
public void hideProgressDialog() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
@Override
public Context getContext() {
return this;
}
/** 跳转首页 */
private void gotoHomeActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
View
层到此就完事了,接下来实现Presenter
和Model
角色的接口和实现类
Presenter
接口和实现类:
public interface ILoginPresenter {
/** 登录操作逻辑处理 */
void login();
/** 登录成功逻辑处理 */
void onLoginSuccess();
/** 登录失败逻辑处理 */
void onLoginFail(String errMsg);
}
public class LoginPresenter implements ILoginPresenter {
private ILoginView mLoginView;
private ILoginModel mLoginModel;
public LoginPresenter(ILoginView loginView) {
mLoginView = loginView;
mLoginModel = new LoginModelImpl(this);
}
@Override
public void login() {
// 对用户名和密码的校验逻辑,这里只简单判空,实际可以加更多校验
if (TextUtils.isEmpty(mLoginView.getUserName())) {
mLoginView.showToast("请输入用户名");
return;
}
if (TextUtils.isEmpty(mLoginView.getPassword())) {
mLoginView.showToast("请输入密码");
return;
}
//判断网络是否可用
if (!NetUtils.checkNetState(mLoginView.getContext())) {
mLoginView.showToast("当前无网络连接,请检查网络");
return;
}
//显示登录进度弹窗
mLoginView.showProgressDialog();
//调用 model 层发起登录请求
mLoginModel.sendLoginRequest(mLoginView.getUserName(), mLoginView.getPassword());
}
/** 登陆成功 */
@Override
public void onLoginSuccess() {
//隐藏登录进度弹窗
mLoginView.hideProgressDialog();
//回调 View 层接口
mLoginView.onLoginSuccess();
}
/** 登陆失败 */
@Override
public void onLoginFail(String errMsg) {
//隐藏登录进度弹窗
mLoginView.hideProgressDialog();
//回调 View 层接口
mLoginView.onLoginFail(errMsg);
}
}
可以看到在LoginPresenter
的实现类当中分别持有了ILoginView
和ILoginModel
两个接口,LoginPresenter
通过这两个接口分别与 LoginActivity 和 LoginModel 进行交互。其中ILoginView
变量是通过构造函数传递进来的,而ILoginModel
则是在构造函数内部创建的。
Model
接口和实现类:
public interface ILoginModel {
/** 发起登录请求 */
void sendLoginRequest(String userName, String password);
}
public class LoginModelImpl implements ILoginModel {
private static final String API_LOGIN = "/mobile/login";
priva
te ILoginPresenter mPresenter;
public LoginModelImpl(ILoginPresenter mPresenter) {
this.mPresenter = mPresenter;
}
@Override
public void sendLoginRequest(String userName, String password) {
String url = BuildConfig.BASE_IP + API_LOGIN;
StringHashMap requestParams = new StringHashMap();
requestParams.put("userName", userName);
requestParams.put("password", password);
HttpDataManager.post(url, requestParams, new HttpCallback() {
@Override
public void onSuccess(String result, Object tag) {
LoginResultBean loginResult = JsonUtils.jsonToObject(result, LoginResultBean.class);
if (loginResult != null) {
if (loginResult.getErrCode() == 200) {
mPresenter.onLoginSuccess();
} else {
mPresenter.onLoginFail(loginResult.getErrMsg());
}
} else {
mPresenter.onLoginFail("登录失败,服务不可用");
}
}
@Override
public void onError(String result, Object tag) {
mPresenter.onLoginFail("登录失败:"+result);
}
}, 100);
}
}
在LoginModelImpl
实现类中持有了ILoginPresenter
接口,通过它与LoginPresenter
实现类进行交户。在LoginModelImpl
实现类中发起请求调用的是HttpDataManager
类的 post 方法,这个类实际上就是你的网络请求框架组件,这里用的是基于开源库的一个简单封装(内部其实还是用的 OkHttpClient)。
HttpDataManager 类的代码:
public class HttpDataManager {
/** 发起 get 请求 */
public static void get(String url, StringHashMap params, HttpCallback callback, int tag) {
RequestParams requestParams = new RequestParams();
requestParams.setAllStrParams(params);
BaseHttpRequest request = new BaseHttpRequest(url, requestParams, callback, tag);
HttpClient.getInstance().get(request);
}
/** 发起 post 请求 */
public static void post(String url, StringHashMap params, HttpCallback callback, int tag) {
RequestParams requestParams = new RequestParams();
requestParams.setAllStrParams(params);
BaseHttpRequest request = new BaseHttpRequest(url, requestParams, callback, tag);
HttpClient.getInstance().post(request);
}
}
这里建了两个类HttpDataManager
和LocalDataManager
分别用来管理网络请求和本地数据存取(File、SharePrefer、DataBase),这里你可以使用流行的开源网络请求库或者其他数据管理库(如 Retrofit、GreenDao 等)。当然对于一个好的架构模式不应该受限于这些库,你可以随意选取。
最后就是在 LoginActivity 当中调用 LoginPresenter 的方法进行登录操作了:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mLoginPresenter = new LoginPresenter(this);
initView();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login:
//开始登录
mLoginPresenter.login();
break;
default:
break;
}
}
到此,一个简单登录页面的 MVP 模式的简单实现就完成了。
如果是第一次接触 MVP,你会明显的发现类文件比传统的写法陡增啊!是的,没错,这也是 MVP 的缺点之一,一个页面要想用 MVP 模式做的比较完美至少要建立五、六个 Java 类,因为 Model 层和 Presenter 层要交互,Presenter 层和 View 层要交互,每个交互都需要接口来进行,即便你使用一些依赖注入框架,可能减少 new 对象的代码,但是 Java 类文件数量依然是少不了的,这是由 MVP 的角色和角色职责功能决定的。
所以你可能感觉原来在一个 Activity 当中就能完成的工作,现在要分这么多文件,但是这样做的代价就是换来了业务逻辑的解耦和职责的划分清晰,别忘了我们当初是为了什么目的来用这个模式的!任何一个模式都会有利有弊,有奉献就会有牺牲,你不可能做到只利用它的优点而不接受它的缺点影响。
评论