『轉(zhuǎn)載』一步一步帶你認識MVP+Retrofit+Rxjava并封裝(一)

序言:這本來是LZ一直想寫的一個系列的文章(哎呀啸罢,說的好像自己挺牛逼似的>_<)當下最流行的設(shè)計模式之一的MVP再配上當下最流行的網(wǎng)絡(luò)請求框架之一的Retrofit+Rxjava(這里我也不引發(fā)戰(zhàn)爭了鉴象,PHP是世界上最好的語言grin: :grin: :grin: )桑嘶,相信大部分人看簡書博客的時候都會經(jīng)常看到高仿某某APP(基于MVP+Retrofit+Rxjava)類的文章让簿,反正LZ是經(jīng)扯3疲看到,好了曹洽,扯淡就扯到這里,下面開始我們的正題:

1辽剧、首先我們來很不情愿的簡單介紹一下MVP
這個東東衣洁,為何說不情愿,首先抖仅,這些概念性的東西我自己都有點看不下去坊夫,其次網(wǎng)上講這個的東西實在是太多了。官方的解釋為經(jīng)典MVC
模式的演化版撤卢,這里我們也不詳細講啥是MVC
了环凿,就是一種古老而又神奇的模式。講一個很簡單的栗子:
有一家早餐店放吩,他們家賣包子智听、饅頭、油條渡紫、粥等等這些東西到推,他們需要用到最重要的東西是面粉(原材料:大米),每次早餐店老板都從一家面粉店(大米店)訂購惕澎,而這些大米都是面粉店老板去農(nóng)民伯伯那里收購的莉测。在這個小例子當中,農(nóng)民伯伯的任務(wù)就是生產(chǎn)出大米唧喉,這其實就相當于MVP
模式中的Model
捣卤,大米就是實體,生產(chǎn)大米就是業(yè)務(wù)的邏輯八孝;面粉店老板負責收購大米然后加工成面粉董朝,這其實就相當于MVP
模式中的Presenter
,負責完成農(nóng)民伯伯和早餐店老板這兩邊的間接交易干跛;最后早餐店老板的任務(wù)就是負責將面粉做成各種各樣的早餐供大家享用子姜,這其實就相當于MVP
模式中的View
,負責將面粉做成各種各樣的食物呈現(xiàn)在大家眼前楼入。好了哥捕,相信通過這個栗子大家應(yīng)該對MVP
模式有一定的了解了,下面來看一張圖:

盜用洋神的圖片

2浅辙、相信用過MVP
的同志們都有體會扭弧,每個人對于MVP
模式的理解都不一樣,這樣導(dǎo)致寫出來的代碼也都風格迥異记舆,但是思想都是一樣的(即降低Model
和View
之間的耦合度鸽捻,使得代碼變的更清晰),所以即將學(xué)習(xí)MVP
的小伙伴們看博客的時候不要驚慌泽腮,因為你們會看到各種的代碼御蒲,下面我們一起來看一下LZ寫的(寫的不好的地方歡迎指正):
(1)、首先我們來看一下Model
诊赊,這部分我理解的就是數(shù)據(jù)獲得的地方厚满,換句話說就是進行網(wǎng)絡(luò)請求的地方(或者本地數(shù)據(jù)的獲取)碧磅,這里我寫了一個Base
類碘箍,將所有的Model
請求數(shù)據(jù)相同的部分都放到了一起:

`

public class BaseModel extends BaseRetrofit {

private static final String TAG = "BaseModel";

protected CygApi mServletApi;   //所有的注解接口

protected Map<String, String> mParams = new HashMap<>();

public BaseModel() {
    super();
    mServletApi = mRetrofit.create(CygApi.class);
}

//獲取公共參數(shù)
@Override
protected Map<String, String> getCommonMap() {
    Map<String, String> commonMap = new HashMap<>();
    commonMap.put("user_id", String.valueOf(UserDao.getInstance().getUserId()));
    commonMap.put("token", String.valueOf(UserDao.getInstance().getToken()));
    return commonMap;
}

//添加一個參數(shù)
protected void addParams(String key, String value) {
    if (TextUtils.isEmpty(key)) {
        Log.e(TAG, "the key is null");
        return;
    }
    mParams.put(key, value);
}

//添加多個參數(shù)
protected void addParams(Map<String, String> params) {
    if (null == params) {
        Log.e(TAG, "the map is null");
        return;
    }
    mParams.putAll(params);}

這里網(wǎng)絡(luò)請求用的是Retrofit+RxJava遵馆,這一部分我打算放到下一篇再講,在這個Base類里面主要添加了公共參數(shù)和添加普通參數(shù)丰榴。來看看一個登錄的Model

`

public class LoginModel extends BaseModel {

public static LoginModel getInstance() {
    return getPresent(LoginModel.class);
}

public void execute(String phone, String password, Observer<User>     observer) {
    addParams("username", phone);
    addParams("password", password);
    Observable observable = mServletApi.getUserInfo(mParams).map(new HttpFunction());
    toSubscribe(observable, observer);
}

}

(2)货邓、這里我是用的單例模式(其實我也不知道這樣寫單例會不會有錯,用類去實例化一個對象>_<我覺得沒啥問題四濒,哈哈哈)换况,然后execute
方法就是進行網(wǎng)絡(luò)請求了,在Presenter
中調(diào)用這個方法就行了盗蟆。然后我們來看一下BasePresenter

`

public class BasePresenter<VIEW> {

private WeakReference<VIEW> mViews;

protected void attachView(VIEW view) {
    mViews = new WeakReference<VIEW>(view);
}

protected VIEW getView() {
    return isViewAttached() ? mViews.get() : null;
}

private boolean isViewAttached() {
    return null != mViews && null != mViews.get();
}

protected void detachView() {
    if (null != mViews) {
        mViews.clear();
        mViews = null;
    }
 }
}

在BasePresenter
里面我只是關(guān)注了View
戈二,按照MVP
模式的理解,我們應(yīng)該在這個里面同時關(guān)注View
和Model
喳资,確實觉吭,很多demo都是這樣干的,但是LZ
前面是用的單例來寫Model
骨饿,所以在BasePresenter
里面就暫時先關(guān)注View
亏栈,還有一點需要說明的是,這里對View
使用的弱引用宏赘,我們都知道View
通常來說都是很大只的存在绒北,為了防止內(nèi)存泄漏,使用弱引用來及時釋放內(nèi)存察署。來看看一個登錄的LoginPresenter

`

public class LoginPresenter extends BasePresenter<LoginView<User>> {

public LoginPresenter(LoginView<User> loginView) {
    attachView(loginView);
}


public void getUserInfo(BaseImpl baseImpl) {
    LoginModel.getInstance().execute(getView().getUserName(), getView().getPassword(), new CygBaseObserver<User>(baseImpl, "正在登錄") {
        @Override
        protected void onBaseNext(User data) {
            UserInfo userInfo = new UserInfo();
            userInfo.setId(data.getId());
            userInfo.setUsername(getView().getUserName());
            userInfo.setToken(data.getToken());
            UserDao.getInstance().deleteAll(UserInfo.class);
            UserDao.getInstance().insertObject(userInfo);
            getView().onRequestSuccessData(data);
        }
    });
}

public void toMainActivity(Activity activity) {
    activity.startActivity(new Intent(activity, MainActivity.class));
}

}

(3)闷游、在登錄的LoginPresenter
中調(diào)用LoginModel
進行網(wǎng)絡(luò)請求,只返回一個成功的回調(diào)贴汪,失敗的回調(diào)我們在內(nèi)部處理掉了脐往,然后在回調(diào)成功之后做相應(yīng)的數(shù)據(jù)操作(該回調(diào)給View
的就回調(diào)給View
,該存本地的就存本地)扳埂。然后來看看我們的View

`

public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView<User> {

@BindView(R.id.al_et_user_name)
TextInputEditText alEtUserName;
@BindView(R.id.al_et_password)
TextInputEditText alEtPassword;

@Override
protected int layoutRes() {
    return R.layout.activity_login;
}

@Override
protected LoginPresenter createPresenter() {
    return new LoginPresenter(this);
}

@Override
protected void initView() {

}

@Override
public String getUserName() {
    return alEtUserName.getText().toString().trim();
}

@Override
public String getPassword() {
    return alEtPassword.getText().toString().trim();
}

@OnClick(R.id.al_btn_login)
public void onViewClicked() {
    if (TextUtils.isEmpty(getUserName())) {
        alEtPassword.setError("用戶名不能為空");
        return;
    }
    if (TextUtils.isEmpty(getPassword())) {
        alEtPassword.setError("密碼不能為空");
        return;
    }
    mPresenter.getUserInfo(this);
}

@Override
public void onBackPressed() {
    super.onBackPressed();
    moveTaskToBack(true);
}

@Override
public void onRequestSuccessData(User data) {
    mPresenter.toMainActivity(this);
}

}

在View
中业簿,就是初始化Presenter
椿肩,然后各種調(diào)Presenter
中的方法撼唾,這里本來是可以在Presenter
中直接調(diào)用toMainActivity()
方法的,為了演示成功回調(diào)之后再回調(diào)給View
赔硫,這里我就多做了一步操作岩调。好了巷燥,接下來我們來看看接口:

`

public interface BaseRequestContract<T> { void    onRequestSuccessData(T data);}

這里寫了一個Base
接口,由于大多時候我們只關(guān)注成功的回調(diào)數(shù)據(jù)号枕,這里我也只寫了一個成功回調(diào)的方法(如果你有其他的需求缰揪,你可以在這里加一些公共的方法),如果你有需要的話你可以在子類中寫錯誤回調(diào)的接口葱淳,接著我們來看看登錄的接口有哪些方法:

`

 public interface LoginView<T> extends BaseRequestContract<T>{ String getUserName(); String getPassword();}

這里我需要獲得用戶的輸入信息钝腺,所以只簡單定義了兩個方法用來獲取用戶名和密碼抛姑。到這里我們的MVP
模式就簡單封裝的差不多了,接下來我們來看一下最終的效果吧:

這里用eclipse+tomcat+mysql
簡單寫了一個登錄接口拍屑,這一部分LZ
在之前的博客中有詳細講解途戒,如有興趣,請移步:
android開發(fā)怎么少的了后端(上)
android開發(fā)怎么少的了后端(中)
android開發(fā)怎么少的了后端(下)

好了僵驰,MVP
的基本封裝就講到這里,下一節(jié)我們再來講一下Retrofit+Rxjava
的簡單封裝及使用唁毒,這里先奉上代碼:
MVP 主工程代碼
MVP module工程代碼
可能很多人就會問了蒜茴,為什么會有兩份呢,這里我給大家看看我的項目工程


LZ
把跟主項目無關(guān)的邏輯都寫到module中去了浆西,這樣也是為了更好的重用代碼粉私。
這是我建的一個android小白的群,各位有興趣的小白歡迎加群共同學(xué)習(xí)近零,也歡迎各位大神進群指導(dǎo)诺核,共勉。群號:541144061

以上內(nèi)容屬于轉(zhuǎn)載久信,內(nèi)容出自作者24K純帥豆

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窖杀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子裙士,更是在濱河造成了極大的恐慌入客,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腿椎,死亡現(xiàn)場離奇詭異桌硫,居然都是意外死亡,警方通過查閱死者的電腦和手機啃炸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門铆隘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人南用,你說我怎么就攤上這事膀钠。” “怎么了训枢?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵托修,是天一觀的道長。 經(jīng)常有香客問我恒界,道長睦刃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任十酣,我火速辦了婚禮涩拙,結(jié)果婚禮上际长,老公的妹妹穿的比我還像新娘。我一直安慰自己兴泥,他們只是感情好工育,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搓彻,像睡著了一般如绸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旭贬,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天怔接,我揣著相機與錄音,去河邊找鬼稀轨。 笑死扼脐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的奋刽。 我是一名探鬼主播瓦侮,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼佣谐!你這毒婦竟也來了肚吏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤台谍,失蹤者是張志新(化名)和其女友劉穎须喂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趁蕊,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡坞生,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掷伙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片是己。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖任柜,靈堂內(nèi)的尸體忽然破棺而出卒废,到底是詐尸還是另有隱情,我是刑警寧澤宙地,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布摔认,位于F島的核電站,受9級特大地震影響宅粥,放射性物質(zhì)發(fā)生泄漏参袱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抹蚀。 院中可真熱鬧剿牺,春花似錦、人聲如沸环壤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郑现。三九已至湃崩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懂酱,已是汗流浹背竹习。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留列牺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓拗窃,卻偏偏與公主長得像瞎领,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子随夸,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容