今天我們聊聊 Android開發(fā)中的 MVP 模式,真的跟科比沒什么關(guān)系,不過科比退役了,MBA 我再也不認識其他人的了,如果科比來學 Android,我想就憑他的傳奇毅力和頭腦,還真差不到哪去,不過要讓這么一個大個子坐一天寫代碼,我想他會瘋掉的,好了,進入正題。
1、MVP簡介
在講MVP設(shè)計架構(gòu)之前,我們要理解這樣三件事情:
1)由于程序要從后臺獲取數(shù)據(jù),大多數(shù)都是異步的。
2)界面和后臺邏輯之間是通過回調(diào)實現(xiàn)調(diào)用的。
3)類之間的依賴要依賴抽象(接口或者抽象類),而非具體實現(xiàn)類。
MVP是Model ViewPresenter 的縮寫,即模型、視圖、主持人。我們之前Android開發(fā)一直都在使用的是MVC,即Model、View、Controlller,后臺邏輯是Model、界面布局是View、Activity是Controller,但是發(fā)現(xiàn)大部分視圖邏輯都堆積在了Activity當中,這樣使Activity不堪重負。
MVP設(shè)計模式其實是在Model和View(Activity)之間增加了一層Presenter。這樣使程序的耦合性更低,更有利于程序的獨立測試,下面是MVP設(shè)計模式中三者之間的關(guān)聯(lián)關(guān)系。
Model:后臺數(shù)據(jù)邏輯和業(yè)務(wù)邏輯,例如從Sqlite數(shù)據(jù)庫,或者網(wǎng)絡(luò)獲取據(jù)。
View:Activity需要的邏輯方法封裝,這里View接口由Activity來實現(xiàn),在
MVP設(shè)計模式中,你可以把Activity看成View
Presenter:是個媒介,你可以把它想象為一個媒婆(哎呀那個帥哥不錯,哎呀那個美女好啊,兩邊撮合),它是界面和后臺邏輯之間紐帶,關(guān)聯(lián)了前端
View和后端Model
請求過程是這樣的,View通知Presenter加載數(shù)據(jù),Presenter調(diào)用Model加載數(shù)據(jù),但是這個過程是異步的,大多數(shù)都需要等待,這樣我們就需要通過回調(diào)來實現(xiàn)異步通信。這里一般會定義一個接口,實現(xiàn)回調(diào)。
2、使用實例
下面以Google官方給出一個實例模型來給大家演示有關(guān)一個用戶登錄的MVP架構(gòu)實現(xiàn)。實現(xiàn)步驟如下:
1)準備界面布局,兩個輸入框,一個按鈕實現(xiàn)登錄
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中需要哪些數(shù)據(jù)和邏輯
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實現(xiàn)
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實現(xiàn),關(guān)聯(lián)前端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,實現(xiàn)調(diào)用
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();
}
}
小結(jié):
之前的 Android APP 太簡單了,根本用不著什么模式,現(xiàn)在 Android應用越來越復雜,從找工作上就可以看出,菜鳥已無崗位需求。所以MVP 也就是到達一定復雜程度后的產(chǎn)物,可維護性也越來越重要了。