詳解Android中的MVP架構(gòu)分解和實(shí)現(xiàn)
1、概述
傳統(tǒng)的Android開發(fā)架構(gòu)一般是MVC模式,
- Model:業(yè)務(wù)邏輯和實(shí)體模型
- View:對(duì)應(yīng)于布局文件
- Controllor:對(duì)應(yīng)于Activity
單獨(dú)從邏輯看起來非常好,與我們做Web開發(fā)時(shí),開發(fā)模式類似,但在實(shí)際開發(fā)中,View對(duì)應(yīng)于布局文件,實(shí)際上關(guān)于該布局文件中的數(shù)據(jù)綁定的操作,事件處理的代碼都在Activity中,Activity既像View又像Controller(MVVP架構(gòu)中包括數(shù)據(jù)綁定),導(dǎo)致Activity中職責(zé)太重,耦合度大。修改和維護(hù)起來非常麻煩。
2、MVP介紹
MVP架構(gòu)中,View 對(duì)應(yīng)于Activity,負(fù)責(zé)View的繪制以及與用戶交互
Model 依然是業(yè)務(wù)邏輯和實(shí)體模型,Presenter 負(fù)責(zé)完成View于Model間的交互。
(1)Model層
模型層之中做的工作是具體業(yè)務(wù)邏輯處理的實(shí)現(xiàn),都伴隨著程序中各種數(shù)據(jù)的處理,復(fù)雜一些的就需要實(shí)現(xiàn)一個(gè)Interface來松耦合了。
(2)View層
視圖層體現(xiàn)的很輕薄,負(fù)責(zé)顯示數(shù)據(jù)、提供友好界面跟用戶交互就行。MVP下Activity和Fragment體現(xiàn)在了這一 層,Activity一般也就做加載UI視圖、設(shè)置監(jiān)聽再交由Presenter處理的一些工作,所以也就需要持有相應(yīng)Presenter的引用。處理一些基本UI邏輯,判斷是否為空。
(3)Presenter層
Presenter這一層處理著程序各種邏輯的分發(fā),收到View層UI上的反饋命令、定時(shí)命令、系統(tǒng)命令等指令后分發(fā)處理邏輯交由Model層做具體的業(yè)務(wù)操作。
MVP架構(gòu)和MVC架構(gòu)區(qū)別:
MVC中是允許Model和View進(jìn)行交互的,而MVP中,Model與View之間的交互由Presenter完成。還有一點(diǎn)就是Presenter與View之間的交互是通過接口的。
3、MVP實(shí)現(xiàn)
百說不如一做。實(shí)現(xiàn)一個(gè)簡(jiǎn)單的登錄操作。
項(xiàng)目結(jié)構(gòu)如下:
(1)Model層實(shí)現(xiàn)
首先實(shí)現(xiàn)User實(shí)體類:
package com.chunsoft.blogcontent.bean; /** * Developer:chunsoft on 2017/2/7 11:19 * Content:實(shí)體類 */ 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; } }
model層主要實(shí)現(xiàn)業(yè)務(wù)邏輯處理,在本文案例中,主要邏輯處理就是登錄,抽取了一個(gè)接口和一個(gè)實(shí)現(xiàn)類,在login操作,模擬登錄操作,Thread.sleep()模擬耗時(shí),由于是耗時(shí)操作,通過一個(gè)回調(diào)接口通知登錄狀態(tài)。
model層接口:
package com.chunsoft.blogcontent.model; import com.chunsoft.blogcontent.RequestCallback; import com.chunsoft.blogcontent.bean.User; /** * Developer:chunsoft on 2017/2/7 11:30 * Email:chun_soft@qq.com * Content:Model層主要處理業(yè)務(wù)方法和實(shí)體模型 */ public interface LoginModel { void login(String username, String password, RequestCallback<User> callback); }
model層接口實(shí)現(xiàn):
package com.chunsoft.blogcontent.model.impl; import com.chunsoft.blogcontent.RequestCallback; import com.chunsoft.blogcontent.bean.User; import com.chunsoft.blogcontent.model.LoginModel; /** * Developer:chunsoft on 2017/2/7 11:31 * Content:Model層的實(shí)現(xiàn) */ public class LoginModelImpl implements LoginModel{ @Override public void login(final String username, final String password, final RequestCallback<User> callback) { //模仿登錄操作 new Thread() { @Override public void run() { try { Thread.sleep(2*1000); } catch (InterruptedException e) { e.printStackTrace(); } if ("chunsoft".equals(username) && "123456".equals(password)) { User user = new User(); user.setUsername(username); user.setPassword(password); callback.onSuccess(user); } else { callback.onFailure("登錄失敗"); } } }.start(); } }
回調(diào)接口:
package com.chunsoft.blogcontent; /** * Developer:chunsoft on 2017/2/7 11:35 * Content:回調(diào)接口 */ public interface RequestCallback<T> { void onSuccess(T datas); void onFailure(String msg); }
(2)View層實(shí)現(xiàn)
對(duì)于View層接口定義,首先考慮功能上的操作,然后考慮:
- 該操作需要什么?(getUserName等)
- 該操作的結(jié)果,對(duì)應(yīng)的反饋?(toMainActivity等)
- 該操作過程中交互友好?( showLoading)
view層接口:
package com.chunsoft.blogcontent.view; import com.chunsoft.blogcontent.bean.User; /** * Developer:chunsoft on 2017/2/7 11:54 * Email:chun_soft@qq.com * Content:view層接口 */ public interface LoginView { String getUserName(); String getPassword(); void showLoading(); void hideLoading(); void toMainActvity(User user); void showFailedError(String msg); }
view層實(shí)現(xiàn),其實(shí)就是Activity,可以看到Activity的代碼量大大減少,且邏輯清晰:
package com.chunsoft.blogcontent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.chunsoft.blogcontent.bean.User; import com.chunsoft.blogcontent.presenter.impl.LoginPresenterImpl; import com.chunsoft.blogcontent.view.LoginView; public class MainActivity extends AppCompatActivity implements LoginView{ private EditText et_mobile,et_password; private ProgressBar pb; private Button btn_login; private LoginPresenterImpl mLoginPresenter = new LoginPresenterImpl(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_mobile = (EditText) findViewById(R.id.et_mobile); et_password = (EditText) findViewById(R.id.et_password); pb = (ProgressBar) findViewById(R.id.pb); btn_login = (Button) findViewById(R.id.btn_login); btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mLoginPresenter.login(); } }); } @Override public String getUserName() { return et_mobile.getText().toString(); } @Override public String getPassword() { return et_password.getText().toString(); } @Override public void showLoading() { pb.setVisibility(View.VISIBLE); } @Override public void hideLoading() { pb.setVisibility(View.INVISIBLE); } @Override public void toMainActvity(User user) { Toast.makeText(this,user.getUsername() + "登錄成功",Toast.LENGTH_SHORT).show(); } @Override public void showFailedError(String msg) { Toast.makeText(this,msg,Toast.LENGTH_SHORT).show(); } }
(3)Presenter層實(shí)現(xiàn)
Presenter層是Model層和View層的橋梁,本文中依然抽象出一個(gè)接口和一個(gè)實(shí)現(xiàn)類,定義時(shí)主要看該功能有什么操作,例如,登錄:
Presenter接口:
package com.chunsoft.blogcontent.presenter; /** * Developer:chunsoft on 2017/2/7 11:49 * Content:Presenter層接口 */ public interface LoginPresenter { void login(); }
Presenter層實(shí)現(xiàn):
package com.chunsoft.blogcontent.presenter.impl; import android.os.Handler; import com.chunsoft.blogcontent.RequestCallback; import com.chunsoft.blogcontent.bean.User; import com.chunsoft.blogcontent.model.LoginModel; import com.chunsoft.blogcontent.model.impl.LoginModelImpl; import com.chunsoft.blogcontent.presenter.LoginPresenter; import com.chunsoft.blogcontent.view.LoginView; /** * Developer:chunsoft on 2017/2/7 11:50 * Content:Presenter層實(shí)現(xiàn) */ public class LoginPresenterImpl implements LoginPresenter { private LoginView loginView; private LoginModel loginModel; private Handler mHandler = new Handler(); //在構(gòu)造函數(shù)中初始化 public LoginPresenterImpl(LoginView loginView) { this.loginModel = new LoginModelImpl(); this.loginView = loginView; } @Override public void login() { loginView.showLoading(); loginModel.login(loginView.getUserName(), loginView.getPassword(), new RequestCallback<User>() { @Override public void onSuccess(final User datas) { //登錄成功 mHandler.post(new Runnable() { @Override public void run() { loginView.toMainActvity(datas); loginView.hideLoading(); } }); } @Override public void onFailure(final String msg) { //登錄失敗 mHandler.post(new Runnable() { @Override public void run() { loginView.showFailedError(msg); loginView.hideLoading(); } }); } }); } }
Presenter層是Model層和View層的橋梁,Model層和View層不直接通信,所以Presenter層需要Model層和View層的實(shí)現(xiàn)類,從View層中獲取重要參數(shù),交給Model 層調(diào)用業(yè)務(wù)邏輯處理,執(zhí)行后的結(jié)果和反饋再交給View層去展示。
本文是簡(jiǎn)單的用MVP架構(gòu)實(shí)現(xiàn)登錄操作,而目前主流開發(fā),將Rxjava、Retrofit和MVP結(jié)合進(jìn)行開發(fā),邏輯更加清晰,下篇文章將詳細(xì)介紹這部分實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 架構(gòu)之?dāng)?shù)據(jù)庫框架搭建
- Android Jetpack架構(gòu)組件Lifecycle詳解
- Android Jetpack架構(gòu)組件 ViewModel詳解
- Android登錄代碼MVP架構(gòu)詳解
- Android應(yīng)用架構(gòu)思想分析
- Android 生命周期架構(gòu)組件使用方法
- Android架構(gòu)組件Room的使用詳解
- Android視圖控件架構(gòu)分析之View、ViewGroup
- 淺析Android系統(tǒng)的架構(gòu)以及程序項(xiàng)目的目錄結(jié)構(gòu)
- Android App的運(yùn)行環(huán)境及Android系統(tǒng)架構(gòu)概覽
- Android操作系統(tǒng)的架構(gòu)設(shè)計(jì)分析
- Android 架構(gòu)之?dāng)?shù)據(jù)庫框架升級(jí)
相關(guān)文章
詳解Java編程中的反射在Android開發(fā)中的應(yīng)用
這篇文章主要介紹了詳解Java編程中的反射在Android開發(fā)中的應(yīng)用,主要來獲取安卓系統(tǒng)的屬性值,需要的朋友可以參考下2015-07-07Android基于HttpUrlConnection類的文件下載實(shí)例代碼
本文通過實(shí)例代碼給大家介紹了Android基于HttpUrlConnection類的文件下載功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-09-09Android自定義PopupWindow仿點(diǎn)擊彈出分享功能
這篇文章主要為大家詳細(xì)介紹了Android自定義PopupWindow仿點(diǎn)擊彈出分享功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02Android FTP 多線程斷點(diǎn)續(xù)傳下載\上傳的實(shí)例
本篇文章主要介紹了Android FTP 多線程斷點(diǎn)續(xù)傳下載\上傳的實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08Android自定義帶動(dòng)畫效果的圓形ProgressBar
這篇文章主要為大家詳細(xì)介紹了Android自定義帶動(dòng)畫效果的圓形ProgressBar,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Android 使用 RxJava2 實(shí)現(xiàn)倒計(jì)時(shí)功能的示例代碼
本篇文章主要介紹了Android 使用 RxJava2 實(shí)現(xiàn)倒計(jì)時(shí)功能的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03Android實(shí)現(xiàn)在ServiceManager中加入自定義服務(wù)的方法詳解
這篇文章主要介紹了Android實(shí)現(xiàn)在ServiceManager中加入自定義服務(wù)的方法,結(jié)合實(shí)例形式分析了Android開發(fā)中ServiceManager自定義服務(wù)的相關(guān)創(chuàng)建與使用方法,需要的朋友可以參考下2017-08-08Android的Fragment的生命周期各狀態(tài)和回調(diào)函數(shù)使用
這篇文章主要介紹了Android的Fragments的生命周期各狀態(tài)和回調(diào)函數(shù)使用,Fragments的生命周期與Activity息息相關(guān),需要的朋友可以參考下2016-02-02深入淺析Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密
一般的手機(jī)沒有root權(quán)限,進(jìn)不去data/data目錄,當(dāng)手機(jī)刷機(jī)了后,擁有root權(quán)限,就可以進(jìn)入data/data目錄,查看我們保存的密碼文件,因此我們需要對(duì)存入的密碼進(jìn)行MD5加密,接下來通過本文給大家介紹Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密,需要的朋友一起學(xué)習(xí)吧2016-04-04Flutter實(shí)現(xiàn)PopupMenu彈出式菜單按鈕詳解
這篇文章主要介紹了Flutter實(shí)現(xiàn)PopupMenu彈出式菜單按鈕,PopupMenuButton是一個(gè)用于創(chuàng)建彈出菜單的小部件,當(dāng)用戶點(diǎn)擊觸發(fā)按鈕時(shí),PopupMenuButton會(huì)在屏幕上方或下方彈出一個(gè)菜單,感興趣想要詳細(xì)了解可以參考下文2023-05-05