序言:這本來是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純帥豆