目錄
1)MVP簡(jiǎn)介
2)MVP實(shí)例
1)MVP簡(jiǎn)介
MVP模式將Activity中的業(yè)務(wù)邏輯全部剝離出來(lái)歇父,Activity只做UI部分的處理盼忌,所有業(yè)務(wù)邏輯層由Presenter層去處理。
分層 | 說(shuō)明 |
---|---|
View | Activity,Fragment绊茧,負(fù)責(zé)處理UI |
Presenter | 業(yè)務(wù)邏輯層铝宵,既能調(diào)用UI,又能請(qǐng)求數(shù)據(jù)源 |
Model | 純業(yè)務(wù)數(shù)據(jù)源的接口與實(shí)現(xiàn) |
M層與V層無(wú)法直接通信华畏,需要通過(guò)P層處理鹏秋。
MVP
2)MVP實(shí)例
實(shí)現(xiàn)一個(gè)登錄請(qǐng)求
假設(shè)我們來(lái)實(shí)現(xiàn)一個(gè)登錄請(qǐng)求。
工程結(jié)構(gòu)
-定義實(shí)體Bean
實(shí)體Bean
public class LoginReq {
private String username;
private String password;
...
}
public class LoginResponse {
private String retcode;
private String retinfo;
private UserData userData;
...
}
public class UserData {
private String name;
private String age;
...
}
-Model層
Model層
- Callback接口, 是Model給Presenter反饋數(shù)據(jù)信息的載體亡笑,需要在Callback中定義數(shù)據(jù)的各種反饋狀態(tài)
//通過(guò)泛型T表示接受任意類(lèi)型
public interface MvpCallback<T> {
/**
* 數(shù)據(jù)請(qǐng)求成功
* @param data 請(qǐng)求到的數(shù)據(jù)
*/
void onSuccess(T data);
/**
* 使用網(wǎng)絡(luò)API接口請(qǐng)求方式時(shí)侣夷,雖然已經(jīng)請(qǐng)求成功但是由
* 于{@code msg}的原因無(wú)法正常返回?cái)?shù)據(jù)。
*/
void onFail(T data);
/**
* 請(qǐng)求數(shù)據(jù)失敗仑乌,指在請(qǐng)求網(wǎng)絡(luò)API接口請(qǐng)求方式時(shí)百拓,出現(xiàn)無(wú)法聯(lián)網(wǎng)、
* 缺少權(quán)限晰甚,內(nèi)存泄露等原因?qū)е聼o(wú)法連接到請(qǐng)求數(shù)據(jù)源衙传。
*/
void onError();
/**
* 當(dāng)請(qǐng)求數(shù)據(jù)結(jié)束時(shí),無(wú)論請(qǐng)求結(jié)果是成功厕九,失敗或是拋出異常都會(huì)執(zhí)行此方法給用戶(hù)做處理蓖捶,通常做網(wǎng)絡(luò)
* 請(qǐng)求時(shí)可以在此處隱藏“正在加載”的等待控件
*/
void onComplete();
}
- 登錄業(yè)務(wù)接口,這里采用了ARouter-IProvider的服務(wù)依賴(lài)注入的方式去解耦服務(wù)止剖,如不需要可不用繼承IProvider
public interface ILoginBiz extends IProvider {
//登錄操作
void login(LoginReq req, MvpCallback mvpCallback);
//存儲(chǔ)登錄信息
void saveUserdata(UserData userdata);
}
- 登錄業(yè)務(wù)實(shí)現(xiàn)腺阳,
@Route(path = "/service/login", name="登錄服務(wù)")
public class LoginBiz implements ILoginBiz {
@Override
public void login(LoginReq req, final MvpCallback mvpCallback) {
Map<String,String> param = new HashMap<String, String>();
//調(diào)用公共組件庫(kù)的OkHttpUtil進(jìn)行網(wǎng)絡(luò)API請(qǐng)求
OkHttpUtil.sendRequestPost(param, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//模擬2秒休眠
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//回調(diào)onComplete
mvpCallback.onComplete();
//模擬response數(shù)據(jù)
UserData userData = new UserData("涂高峰","18");
LoginResponse loginResponse = new LoginResponse("000000","登錄成功",userData);
//回調(diào)onSuccess
mvpCallback.onSuccess(loginResponse.getUserData());
}
});
}
@Override
public void saveUserdata(UserData userdata) {
}
@Override
public void init(Context context) {
}
}
-View層落君,View接口是Activity層和Presenter層的中間層,它用于根據(jù)具體業(yè)務(wù)需要亭引,為Presenter層提供調(diào)用Activity中具體UI操作的方法绎速。
View層
- IMvpView,抽象出的公共View
public interface IMvpView {
/**
* 顯示正在加載view
*/
void showLoading();
/**
* 關(guān)閉正在加載view
*/
void hideLoading();
/**
* 顯示提示
* @param msg
*/
void showToast(String msg);
}
- ILoginView焙蚓,登錄業(yè)務(wù)View纹冤,繼承了IMvpView。
public interface ILoginView extends IMvpView {
/**
* 登錄請(qǐng)求成功提示
*/
void loginSuccess(UserData userData);
/**
* 登錄請(qǐng)求失敗提示
*/
void loginFail(String text);
}
-Presenter層购公,具體的業(yè)務(wù)邏輯處理Java類(lèi)萌京,不含任何Android-API操作,負(fù)責(zé)請(qǐng)求數(shù)據(jù)源宏浩,并對(duì)數(shù)據(jù)源反饋?zhàn)鎏幚怼?/p>
Presenter層
- MvpPresenter知残,抽象出公共的Presenter,
public class MvpPresenter<V extends IMvpView> {
/**
* 綁定的view
*/
private V mvpView;
/**
* 綁定view比庄,一般在初始化中調(diào)用該方法
*/
public void attachView(V view){
this.mvpView = view;
}
/**
* 斷開(kāi)view求妹,一般在onDestroy中調(diào)用
* 對(duì)于Activity異常銷(xiāo)毀導(dǎo)致mvpView空指針
* 采用attachView和detachView,將view與activity生命周期綁定
*/
public void detachView(){
this.mvpView = null;
}
/**
* 是否與View建立連接
* 每次調(diào)用業(yè)務(wù)請(qǐng)求的時(shí)候都要出先調(diào)用方法檢查是否與View建立連接
*/
public boolean isViewAttached(){
return this.mvpView != null;
}
/**
* 獲取連接的view
*/
public V getView(){
return this.mvpView;
}
/**
* 獲取連接的view名稱(chēng)
*/
public String getViewName(){
return this.mvpView.getClass().getSimpleName();
}
}
- LoginPresenter佳窑,登錄業(yè)務(wù)Presenter制恍,繼承了MvpPresenter。
public class LoginPresenter extends MvpPresenter<ILoginView> {
//依賴(lài)注入發(fā)現(xiàn)服務(wù)
@Autowired(name = "/service/login")
LoginBiz loginBiz;
public LoginPresenter() {
// this.loginBiz = new LoginBiz();
//依賴(lài)注入
ARouter.getInstance().inject(this);
}
public void login(LoginReq req){
if (!isViewAttached()){
//如果沒(méi)有View引用就不加載數(shù)據(jù)
return;
}
getView().showLoading();
loginBiz.login(req, new MvpCallback() {
@Override
public void onSuccess(final Object data) {
if (isViewAttached()){
MainLooper.runOnUiThread(new Runnable() {
@Override
public void run() {
getView().loginSuccess((UserData) data);
}
});
}
}
@Override
public void onFail(Object data) {
}
@Override
public void onError() {
}
@Override
public void onComplete() {
if (isViewAttached()){
MainLooper.runOnUiThread(new Runnable() {
@Override
public void run() {
getView().hideLoading();
}
});
}
}
});
}
}
-Activity,登錄業(yè)務(wù)Activity神凑,實(shí)現(xiàn)了ILoginView
public class MainActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{
private LoginPresenter loginPresenter;
private TextView txt;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = findViewById(R.id.txt);
progressBar = findViewById(R.id.progressBar);
findViewById(R.id.success_btn).setOnClickListener(this);
//初始化Presenter
loginPresenter = new LoginPresenter();
//綁定View引用
loginPresenter.attachView(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//斷開(kāi)View引用
loginPresenter.detachView();
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.success_btn:
LoginReq loginReq = new LoginReq("tgf","123");
loginPresenter.login(loginReq);
break;
}
}
@Override
public void showLoading() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
progressBar.setVisibility(View.GONE);
}
@Override
public void showToast(String msg) {
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public void loginSuccess(UserData userData) {
txt.setText("姓名: "+userData.getName() + "年齡"+ userData.getAge());
}
@Override
public void loginFail(String text) {
}
}
-其他工具類(lèi)
public class MainLooper extends Handler {
private static MainLooper instance = new MainLooper(Looper.getMainLooper());
protected MainLooper(Looper looper) {
super(looper);
}
public static MainLooper getInstance() {
return instance;
}
public static void runOnUiThread(Runnable runnable) {
if(Looper.getMainLooper().equals(Looper.myLooper())) {
runnable.run();
} else {
instance.post(runnable);
}
}
}
參考資料
谷歌官方架構(gòu)藍(lán)圖Android Architecture Blueprints
Android MVP架構(gòu)搭建