最近在研究MVP的使用,看了幾篇介紹的,
綜合了Google的MVPdemo介紹。簡單的說一下。
https://github.com/zhuyongit/MVPDemo。這篇說的感覺還不錯,分析的挺透徹。
http://www.lxweimin.com/p/14283d8d3a60這個里面有Google的MVP簡單的介紹。
一:基本概念
不管是MVC還是MVP , 都是為了將數據,處理邏輯,與界面分離 , 以達到低耦合的效果 。MVP模式,主要是面向接口編程 , 將Model與View都抽象成接口,用一個Presenter來關聯View與Model,Presenter做到一個綁定數據控制界面的中間者 。
下面簡單的畫下UML圖幫助理解:
MVC:M(Model)V(View)C(Controller)
MVP:M(Model)V(View)P(Presenter)
MVC:
MVP:P層持有M層和V層的對象,將M與V關聯起來 , 在MVP中將Model與View的操作接口化 , 通過接口回調來完成數據的傳遞 。
傳統的MVP不能更直觀的看到IView中的方法和Presenter中的方法的關聯。我這里多了一個contract包:里面放的是契約接口。更能直接明了的看到View和Presenter之間的方法。具體的模型圖:
下面開始敲代碼:
①首先先把基類的Contract和BaseActivity定義好。
/**
* Created by pepys on 2017/5/26.
* description:Contract基類
*/
public interface BaseContract {
interface View {
/**
* 顯示loading
*/
void showProgress();
/**
* 隱藏loading
*/
void hideProgress();
}
interface Presenter<T> {
/**
* 初始化操作
*/
void onStart();
/**
* 關聯View
* @param view
*/
void attachView(@NonNull T view);
/**
* 防止內存泄漏,在presneter銷毀時同事銷毀view
*/
void onDestroy();
}
}
public abstract class BaseActivity<V,T extends BaseContract.Presenter<V>> extends FragmentActivity {
protected T mPresneter ;
/**
* create presenter
* @return
*/
protected abstract T createPresenter();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*創建Presenter*/
mPresneter = createPresenter();
/*內存泄漏 , 關聯View*/
mPresneter.attachView((V) this);
setContentView(getLayoutID());
findViewByID();
}
protected abstract int getLayoutID();
protected abstract void findViewByID();
@Override
protected void onDestroy() {
super.onDestroy();
mPresneter.onDestroy();
}
}
②基類的presenter實現,主要為了管理View。防止內存泄漏.
public abstract class BasePresenterImpl<T> implements BaseContract.Presenter<T> {
protected T mView;
@Override
public void attachView( T view) {
this.mView = view;
}
@Override
public void onDestroy() {
cancelRequest();
mView = null;
}
/**
* 這個計劃是在view銷毀的時候同時取消請求
*/
public void cancelRequest() {
//// TODO: 2017/5/26
}
}
③編寫業務Contract契約接口,定義業務接口,如果邏輯復雜的話,View 里面的接口可能會比較多~
public interface LoginContract {
interface View extends BaseContract.View {
/*得到用戶名*/
String getName();
/*得到密碼*/
String getPassword();
void loginSuccess();
void loginFailure();
}
interface Presenter extends BaseContract.Presenter {
/*執行請求處理*/
void login();
}
interface Model {
HashMap<String,String> resultMap = new HashMap<>();
void login(String name, String psw, CallbackListener callback);
}
}
④ 繼續敲Model實現類。
/**
* Created by pepys on 2017/5/26.
* description: 這里才是真正的數據請求
*/
public class LoginModelImpl implements LoginContract.Model {
@Override
public void login(final String name, String psw, final CallbackListener callback) {
//模擬請求
callback.before();
try {
Thread.sleep(1000*4);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(name.equals("001")){
resultMap.put("status","成功");
callback.onSuccess(resultMap);
}else{
resultMap.put("status","失敗");
callback.onFailure(resultMap);
}
callback.after();
}
}
⑤ 編寫presenter實現類 , 定一個兩個接口的引用,Model在創建類的時候就創建 , 而View則是通過創建Presenter對象進行傳遞 。
/**
* Created by pepys on 2017/5/26.
* description:Presneter 這是是處理view和model的地方
*/
public class LoginPresneterImpl extends BasePresenterImpl implements LoginContract.Presenter {
/**
* 持有view引用
*/
private LoginContract.View view;
/**
* 持有model引用
*/
private LoginContract.Model model = new LoginModelImpl();
public LoginPresneterImpl(LoginContract.View view) {
this.view = view;
}
@Override
public void login() {
model.login(view.getName(), view.getPassword(), new CallbackListener() {
@Override
public void before() {
view.showProgress();
}
@Override
public void onSuccess(HashMap hashMap) {
view.loginSuccess();
}
@Override
public void onFailure(HashMap hashMap) {
view.loginFailure();
}
@Override
public void after() {
view.hideProgress();
}
});
}
@Override
public void onStart() {
//這里可以放入進界面就請求的
}
}
⑥Activity實現View接口,在presenter中交互。
public class MainActivity extends BaseActivity<LoginContract.View,BaseContract.Presenter<LoginContract.View>> implements LoginContract.View,View.OnClickListener{
private LoginPresneterImpl presneter ;
private EditText logion_name,logion_pwd;
private Button login_submit;
@Override
protected BaseContract.Presenter<LoginContract.View> createPresenter() {
return presneter = new LoginPresneterImpl(MainActivity.this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutID() {
return R.layout.activity_main;
}
@Override
protected void findViewByID() {
logion_name = (EditText) findViewById(R.id.logion_name);
logion_pwd = (EditText) findViewById(R.id.logion_pwd);
login_submit = (Button) findViewById(R.id.login_submit);
login_submit.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.login_submit:
presneter.login();
break;
}
}
@Override
public void showProgress() {
Toast.makeText(this,"請稍等..",Toast.LENGTH_LONG).show();
}
@Override
public void hideProgress() {
}
@Override
public String getName() {
return logion_name.getText().toString();
}
@Override
public String getPassword() {
return logion_pwd.getText().toString();
}
@Override
public void loginSuccess() {
Toast.makeText(this,"成功..",Toast.LENGTH_LONG).show();
}
@Override
public void loginFailure() {
Toast.makeText(this,"失敗..",Toast.LENGTH_LONG).show();
}
}
MVP現在在Android中應用越來越廣泛了 。雖然項目文件會比較多 , 但是如果管理好接口類,結構清晰,使用起來還是比較方便的。
具體的demo已經放到github上。
https://github.com/PepysZhu/MVPDemo