三个男躁一个女,国精产品一区一手机的秘密,麦子交换系列最经典十句话,欧美 国产 综合 欧美 视频

start_time: 2025-06-04 12:34:58 +0800

Android MVP從懵逼到入門:登陸業務實踐

96
星際之痕
IP屬地: 陜西
1.2 2016.07.13 10:47 字數 2400

MVP簡介

最近幾天在啃MVP,現在的你或許跟幾天前的我一樣,對MVP還是一臉懵逼,雖然MVP三個字母都認識,但連在一起卻不明白到底是個什么東東,沒關系,快來干了這碗雞湯,立馬從懵逼到入門,入不了門你來打我,文末統計人數。


首先,MVP是一種設計模式,或者說架構。Google把它列入Android Architecture Blueprints--Android 架構藍圖,并給出了官方的例子來解釋如何實現MVP。本文實現的登陸功能就是根據MVP基礎架構Demo來實現的。

其次,MVP從何而來?想必都知道是MVC的演化版本,現在比較流行,被廣大開發者所認可。被認可的原因我在這里總結一下:

  • 代碼清晰,容易理解(掌握MVP的前提下)
  • 簡化了萬能的Activity的邏輯
  • 解耦了View和Model
  • 方便單元測試

一直以來,在MVC模式中Activity的萬能角色就備受詬病,一旦邏輯越來越復雜,Activity就越來越臃腫,承擔越來越多的職責,代碼閱讀起來費勁,維護成本跟著提高,而且,在MVC模式中,View 和 Model直接交互,耦合度高,違背了軟件開發“高類聚、低耦合”的設計目標--于是MVP橫空出世。

關于MVP的理論知識就嗶嗶這些,想要詳細了解的童鞋回頭自己做功課去,這里不是重點,本文的重點是把MVP模式實踐起來。

MVP實現登陸

mvp.png

這是google samples TODO-MVP項目中的MVP圖解。因為本人學習MVP主要也是根據谷歌官方demo來的,所以,這個圖直接拿來。這個圖怎么看?

  • 分為左右兩部分,左邊沒顏色的部分包含的內容是Model,這里面包含了數據實體模型、數據訪問接口、SQLite數據庫操作、網路數據操作、數據內存緩存,這些都是Model要做的事情,跟MVC沒什么差別;

  • 右邊...那個什么顏色的背景(色盲晚期),注意那個Activity,我們看到VIEW和PRESENTER都被放在了Activity里邊,而VIEW的實現類在這里用的是Fragment;

  • 隱藏內容:這里面其實還有一個內容--契約類,也就是項目里的XXXContract.java類,是一個接口類,作用是定義VIEW接口和PRESENTER接口提供的接口方法。這個類原則上不屬于MVP模式里的任何角色,所以沒在上圖出現,可以理解。

    先看看效果 不方便看視頻的就看看圖吧!
    [圖片上傳失敗...(image-32673-1521790364530)]


[圖片上傳失敗...(image-17e711-1521790364530)]

  • 1.創建View接口和Presenter接口基類
    BaseView作為View接口基類,定義了一個重要的接口:

     void setPresenter(T presenter);
    

[圖片上傳失敗...(image-220445-1521790364530)]
[圖片上傳失敗...(image-edaa6-1521790364530)]

這其實是MVP的一個關鍵點,通過這個接口,View的實現類(即Fragment)就持有了Presenter的實例,于是,View就可以通過Presenter來操作Model中的數據接口了。如果你要實現MVP模式,記住,不管三七二十一,先寫這個基佬,哦,不對,是基類。

Presenter接口基類里同樣定義了一個接口:

  void start();

這個方法就是直接操作Model的,比如加載數據。通過這兩個基類的定義的接口就能看出,View和Model不直接交互,而是通過Presenter來操作,這是與MVC的不同之處。

  • 2.登陸契約類LoginContract
    public interface LoginContract {

    interface Presenter extends BasePresenter {
          void login();
          void reset();
    }
    
    interface View extends BaseView<Presenter> {
          String getUserEmail();
          String getPassword();
    
          boolean isEmailValid(String email);
          boolean isPasswordValid(String password);
    
          boolean setEmailError(String error);
          boolean setPasswordError(String error);
    
          void showLoginProgress(boolean show);
          void resetEditView();
          void toMainAct();
          void showFailedError();
      }
    }
    

    這個類是首次出現于google的mvp示例中,以前的MVP模式并未見到,這個類定義了View接口和Presenter接口為對方的實例提供的方法。

    比如,我在View中可以獲取用戶輸入的郵箱和密碼,判斷郵箱密碼是否有效,設置郵箱密碼輸入框錯誤提示信息,顯示登陸ProgressBar等,同樣,在Presenter接口中,提供了登陸和重置兩個功能,用戶通過View上的兩個按鈕,響應Presenter對應的接口,執行相關的業務邏輯。

    這個契約類的好處是方便接口統一管理、修改,同時,內容清晰,一目了然。

  • 3.View的實現類LoginFragment implements LoginContract.View
    實現接口定義的各個方法,必須持有Presenter,并通過接口

    void setPresenter(T presenter)
    

為其賦值。

注意官方的demo說明里有這段內容:

Note: in a MVP context, the term "view" is overloaded:

The class android.view.View will be referred to as "Android View"
The view that receives commands from a presenter in MVP, will be simply called "view".

我來獻個丑,翻譯一下:

注意:在MVP的上下文里,“view”一詞有多重含義:

  • android.view.View被稱為“Android View”
  • 在MVP中,從presenter接收命令的view將被簡單地稱為“view”。

什么意思?

我的理解是這樣的:MVP中的VIEW由兩部分組成,一個是view接口,比如上面的LoginContract.View接口;一個是該接口的實現類,比如上面的LoginFragment。view接口負責與presenter交互,presenter調用view接口定義方法來操作view的實現類;具體實現都是在android.view.View里實現的,即LoginFragment。

  • 4.Presenter的實現類LoginPresenter implements LoginContract.Presenter
    實現接口定義的各個方法,必須持有Model對象和View對象

    private final UserRepository mUserRepository;
    private final LoginContract.View mLoginView;
    

然后,你想讓View干嘛,調用View相對應的接口就行了,想要什么數據,想對數據做什么操作,調用Model對象的對應方法就行了;或許你已經發現了:

Presenter對View的操作都是通過接口來完成的。

  • 5.Activity的角色,看Google官方Sample里怎么介紹的:

It uses fragments for two reasons:

The separation between Activity and Fragment fits nicely with this implementation of MVP: the Activity is the overall controller that creates and connects views and presenters.
Tablet layout or screens with multiple views take advantage of the Fragments framework.

獻丑二進宮:

(MVP中的View實現)使用Fragment有兩個原因:

Activity與Fragment之間的分離很好的符合了MVP的實現:Activity作為整體控制器來創建和連接views與presenters。
Tablet布局或者屏幕上有多個views的布局可以很好的利用Fragments框架。

在MVP模式里,Activity的功能變得簡單了很多,一是創建View布局(Fragment),二是實例化Presenter(LoginPresenter),并將View(Fragment)作為參數,傳入到Presenter(LoginPresenter)中,在Presenter(LoginPresenter)構造函數中傳遞給Presenter(LoginPresenter)持有的View對象,然后View對象調用setPresenter方法,將自身this傳遞給View實例(Fragment)。也就是上面說的“創建和連接views與presenters。

來看看Activity代碼多簡單:
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

        LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);        
        // Create the view        
        if (loginFragment == null) {            
            loginFragment = LoginFragment.newInstance("LOGIN_FRAGMENT");        
        }

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
        transaction.add(R.id.contentFrame, loginFragment);        
        transaction.commit(); 
   
        // Create the presenter        
        new LoginPresenter(
                getApplicationContext(),                
                UserRepository.getInstance(
                    UserLocalDataSource.getInstance(getApplicationContext()),
                    UserRemoteDataSource.getInstance()),                
                loginFragment);    
    }
  }

至此,MVP模式里的VP就可以運行起來了,連通起來了。下面來說說Model。如果對MVC的Model非常熟悉可以跳過。

  • 6.Model的創建
    在目錄結構圖中,整個data package里的都是Model的內容,包括實體模型(User類)、本地數據庫操作(local package)、遠程數據訪問(remote package)三部分,跟在MVC里并無差別,這里不展開介紹。

    業務邏輯需要什么樣的數據實體、數據操作,在對應的包里面構建就行了,這里要提到的是,Presenter對Model的持有,這里也是通過接口實現的,間接通過UserDataSource接口類,直接通過UserDataSource的實現類UserRepository。而UserRepository同時持有對本地數據和遠程數據操作的對象:
    private final UserDataSource mLocalDataSource;
    private final UserDataSource mRemoteDataSource;

MVP實踐總結

使用MVP模式也有一些不盡如人意的地方,比如,類和接口變多了,代碼也多了,項目大了可能會不好管理,但這都不是事,用多點代碼、多點類文件換取低耦合度、結構清晰、容易理解、易擴展的架構,這買賣值了。

第一遍看的時候懵逼沒關系,再看一遍,認真的解讀MVP的設計思路,參考代碼,發現其實真的是很清晰的思路,并不難,難的是啃下來的決心。這碗雞湯我干了,你們隨意。

相信看完這篇文章會對你理解MVP有所幫助,如果你還是一臉懵逼的話,請舉起手來:
[圖片上傳失敗...(image-e459b1-1521790364530)]

最后,奉上本文的源碼GitHub:Login-MVP-Architecture,如果覺得有用,點個Star表示支持。

最后編輯于 :2018-03-23 15:35:53
?著作權歸作者所有,轉載或內容合作請聯系作者
序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 230919 評論 6 贊 546
序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 99862 評論 3 贊 429
文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
8 開封第一講書人 閱讀 179438 評論 0 贊 384
文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
8 開封第一講書人 閱讀 64096 評論 1 贊 319
正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶點故事 閱讀 72822 評論 6 贊 414
文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
8 開封第一講書人 閱讀 56166 評論 1 贊 330
那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 44134 評論 3 贊 450
文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
8 開封第一講書人 閱讀 43328 評論 0 贊 291
序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 49839 評論 1 贊 338
正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶點故事 閱讀 41561 評論 3 贊 362
正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶點故事 閱讀 43793 評論 1 贊 375
序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 39244 評論 5 贊 365
正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶點故事 閱讀 44969 評論 3 贊 351
文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
8 開封第一講書人 閱讀 35361 評論 0 贊 28
文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
8 開封第一講書人 閱讀 36701 評論 1 贊 296
我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 閱讀 52538 評論 3 贊 400
正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶點故事 閱讀 48751 評論 2 贊 383
end_time: 2025-06-04 12:34:58 +0800 Completed in 136.712837ms 主站蜘蛛池模板: 溧水县| 剑阁县| 徐汇区| 永兴县| 墨玉县| 延津县| 烟台市| 册亨县| 临洮县| 页游| 临泉县| 邵阳市| 饶平县| 徐闻县| 万山特区| 左贡县| 石阡县| 高青县| 清远市| 晋城| 安陆市| 光泽县| 屯昌县| 汝南县| 万盛区| 图们市| 西充县| 宣恩县| 祁阳县| 蓬莱市| 西峡县| 策勒县| 大港区| 嫩江县| 梓潼县| 朝阳县| 莎车县| 汕尾市| 安达市| 永州市| 巨野县|