今天我们聊聊 Android开发中的 MVP 模式,真的跟科比没什么关系,不过科比退役了,MBA 我再也不认识其他人的了,如果科比来学 Android,我想就凭他的传奇毅力和头脑,还真差不到哪去,不过要让这么一个大个子坐一天写代码,我想他会疯掉的,好了,进入正题。
1、MVP简介
在讲MVP设计架构之前,我们要理解这样三件事情:
1)由于程序要从后台获取数据,大多数都是异步的。
2)界面和后台逻辑之间是通过回调实现调用的。
3)类之间的依赖要依赖抽象(接口或者抽象类),而非具体实现类。
MVP是Model ViewPresenter 的缩写,即模型、视图、主持人。我们之前Android开发一直都在使用的是MVC,即Model、View、Controlller,后台逻辑是Model、界面布局是View、Activity是Controller,但是发现大部分视图逻辑都堆积在了Activity当中,这样使Activity不堪重负。
MVP设计模式其实是在Model和View(Activity)之间增加了一层Presenter。这样使程序的耦合性更低,更有利于程序的独立测试,下面是MVP设计模式中三者之间的关联关系。
Model:后台数据逻辑和业务逻辑,例如从Sqlite数据库,或者网络获取据。
View:Activity需要的逻辑方法封装,这里View接口由Activity来实现,在
MVP设计模式中,你可以把Activity看成View
Presenter:是个媒介,你可以把它想象为一个媒婆(哎呀那个帅哥不错,哎呀那个美女好啊,两边撮合),它是界面和后台逻辑之间纽带,关联了前端
View和后端Model
请求过程是这样的,View通知Presenter加载数据,Presenter调用Model加载数据,但是这个过程是异步的,大多数都需要等待,这样我们就需要通过回调来实现异步通信。这里一般会定义一个接口,实现回调。
2、使用实例
下面以Google官方给出一个实例模型来给大家演示有关一个用户登录的MVP架构实现。实现步骤如下:
1)准备界面布局,两个输入框,一个按钮实现登录
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="260dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="center_horizontal"
tools:context="com.moliying.demo01.MainActivity">
android:layout_width="match_parent"
android:id="@+id/edit_username"
android:hint="Username..."
android:drawableLeft="@drawable/ic_action_person"
android:layout_height="wrap_content" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password..."
android:drawableLeft="@drawable/ic_action_accounts"
android:id="@+id/edit_password"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_action_accept"
android:text="Login"
android:onClick="login"
/>
android:layout_width="wrap_content"
android:visibility="gone"
android:id="@+id/progress"
android:layout_height="wrap_content" />
2)准备View接口,这里要看Activity中需要哪些数据和逻辑
package com.moliying.demo01;
/**
* Created by moliying.com on 12.
*/
public interface LoginView {
public void showProgress();
public void hideProgress();
public void setUsernameError();
public void setPasswordError();
public void navigateToHome();
3)准备Model接口
public interface LoginInteractor {
interface OnLoginListener{
void onUsernameError();
void onPasswordError();
void onSuccess();
}
public void login(String username, String password, OnLoginListener listener);
4)准备Model实现
package com.moliying.demo01;
import android.os.Handler;
import android.text.TextUtils;
/**
* Created by moliying.com on 2016/12/22.
*/
public class LoginInteractorImpl implements LoginInteractor {
@Override
public void login(final String username, final String password, final OnLoginListener listener) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
boolean error = false;
if(TextUtils.isEmpty(username)){
listener.onUsernameError();
error = true;
}
if (TextUtils.isEmpty(password)) {
listener.onPasswordError();
error = true;
}
if (!error) {
listener.onSuccess();
}
}
},2000);
}
}
5)准备Presenter接口
package com.moliying.demo01;
/**
* Created by moliying.com on 2016/12/22.
*/
public interface LoginPresenter {
public void login(String username, String password);
public void onDestory();
}
6)准备Presenter实现,关联前端View和后端Model
package com.moliying.demo01;
/**
* Created by moliying.com on 2016/12/22.
*/
public class LoginPresenterImpl implements LoginPresenter,LoginInteractor.OnLoginListener {
LoginInteractor loginInteractor;
LoginView loginView;
public LoginPresenterImpl(LoginView loginView){
this.loginView = loginView;
this.loginInteractor = new LoginInteractorImpl();
}
@Override
public void login(String username, String password) {
if (loginInteractor != null) {
loginInteractor.login(username,password,this);
}
}
@Override
public void onDestory() {
}
@Override
public void onUsernameError() {
if (loginView != null) {
loginView.setPasswordError();
loginView.hideProgress();
}
}
@Override
public void onPasswordError() {
if (loginView != null) {
loginView.setPasswordError();
loginView.hideProgress();
}
}
@Override
public void onSuccess() {
if (loginView != null) {
loginView.navigateToHome();
}
}
}
7)准备Activity,实现调用
package com.moliying.demo01;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements LoginView {
EditText username;
EditText password;
ProgressBar progress;
LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(),0);
}
});
initViews();
loginPresenter = new LoginPresenterImpl(this);
}
private void initViews() {
username = (EditText) findViewById(R.id.edit_username);
password = (EditText) findViewById(R.id.edit_password);
progress = (ProgressBar) findViewById(R.id.progress);
}
public void login(View view) {
String un = username.getText().toString();
String pwd = password.getText().toString();
loginPresenter.login(un,pwd);
}
@Override
public void showProgress() {
progress.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
progress.setVisibility(View.GONE);
}
@Override
public void setUsernameError() {
username.setError("Username error...");
}
@Override
public void setPasswordError() {
password.setError("Password error...");
}
@Override
public void navigateToHome() {
Toast.makeText(MainActivity.this, "to main...", Toast.LENGTH_SHORT).show();
}
}
小结:
之前的 Android APP 太简单了,根本用不着什么模式,现在 Android应用越来越复杂,从找工作上就可以看出,菜鸟已无岗位需求。所以MVP 也就是到达一定复杂程度后的产物,可维护性也越来越重要了。