Android Mvp+DataBinding架構模式詳解
阿新 • • 發佈:2019-02-14
MVP模式的使用
一. MVC與MVP設計模式的區別
MVC:使用者發出事件的時候,view層發出指令到controller層,controller層去通知model層更新資料,更新完資料後返回給view層展示。
MVC反映到Android工程上
- V:layout.xml佈局檔案就相應於MVC的View層
- M:各種javaBean,第三方庫類,ApiService,一系列helper和manager
- C:activity
MVC的缺點:
- layout作為view層,控制能力太弱。
- 程式碼寫在activity中,造成了activity即是controller層,又是view層的現象
- view層和model層相互可知,兩者之間存在耦合
MVP:
對於Android來說,MVP的model層為資料處理層;View為試圖,比如activity和fragment;Presenter為業務邏輯處理層和中間層,主持人的角色,處理流程控制。相比於MVC,MVP中的view層和model層不再相互可知,完全的解耦 。使用presenter充當橋樑的作用,
用於操作view層發出的事件傳到presenter層中,presenter層通知model層進行資料處理,並且將處理完成的資料返回給 view層顯示。
另外view層和presenter層也是解耦開來,兩者之間的通訊可以通過介面實現,在activity或者fragment實現view層定義好的介面,在presenter中通過介面呼叫方法 最好的方式是使用fragment作為view層,而activty則用於建立view層和presenter層的一個控制器。
二. MVP模式詳細解析
使用MVP,至少經歷以下幾個步驟:(M不能呼叫P層)
- 建立IPresenter介面,定義好所有的業務邏輯介面,並且建立它的實現類PresenterCompl。
- 建立IView介面,定義好所有試圖邏輯的介面,實現類就是當前的Activity和Fragment
- Activity 裡包含了一個 IPresenter,而 PresenterCompl 裡又包含了一個 IView 並且依賴了 Model。Activity 裡只保留對 IPresenter 的呼叫,其它工作全部留到 PresenterCompl 中實現。
- Model :不是傳統意義上的Model,而是一個ModelManager資料處理中心,可以處理網路資料,資料庫,檔案以及關於Android中的四大元件的互動包含BroadcastReceiver,Service中的,都可以集中在這裡面處理。
某一個模組的網路處理可以寫一個NetWorkModel,資料庫操作寫一個DbModel(或者只寫一個RepositoryModel同時處理網路和資料庫的資料,建議三個Model都寫),同時繼承BaseMode。Model層並不是必須有的,但是一定會有 View 和 Presenter。(也可以在P層處理簡單的資料,怎麼方便怎麼來,不拘於模式) ViewMode:使用RecyclerView的Adapter,採用ViewModel+IView的方式,IView的setData方法中處理資料繫結
MVP的實踐:
1. Base層BasePresenter
public abstract class BasePresenter<V> {
private Reference<V> mUIRef;
protected V mView;
void onAttach(V view) {
mUIRef = new WeakReference<V>(view);
mView = mUIRef.get();
}
void onDetach() {
if (mUIRef != null) {
mUIRef.clear();
mUIRef = null;
}
}
protected V getView() {
if (mUIRef == null) {
return null;
}
return mUIRef.get();
}
public boolean isUIAttached() {
return mUIRef != null && mUIRef.get() != null;
}
}
- Base層BaseMVPActivity
public abstract class BaseMVPActivity<V, P extends BasePresenter<V>> extends AppCompatActivity {
private P presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
presenter = createPresenter();
presenter.onAttach((V) this);
initView();
initListener();
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.onDetach();
}
public abstract P createPresenter();
public P getPresenter() {
return presenter;
}
public abstract int getLayoutId();
public abstract void initView();
public abstract void initListener();
}
- Base層Model:
/**
* 可用於資料操作,網路,資料庫,和檔案等等
* NetWorkModel 網路操作
* DatabaseModel 資料庫操作
* RepositoryModel(同時調NetWorkModel和DatabaseModel) 同時操作網路和資料庫
* 以上看情況選擇
* @author : liujian
* @since : 2017/9/3
*/
public interface BaseModel<D> {
interface LoadTaskCallBack<D> {
void onTasksLoaded(List<D> list);
void onLoadFailed();
}
interface UpdateTaskCallBack {
void onUpdateSucceed();
void onUpdateFailed();
}
void getData(LoadTaskCallBack callBack);
void saveData(D d, UpdateTaskCallBack callBack);
void updateData(D d, UpdateTaskCallBack callBack);
void deleteData(String id, UpdateTaskCallBack callBack);
void deleteAllData(UpdateTaskCallBack callBack);
}
- View層介面ILoginView:
public interface ILoginView {
void clearTextView();
void onLoginResult(boolean result);
void showEmptyInfo();
}
- Presenter層介面ILoginPresenter
public abstract class ILoginPresenter extends BasePresenter<ILoginView>{
public abstract void clear();
public abstract void login(String name, String password);
}
- Model層介面ILoginModel
public interface ILoginModel {
public interface OnLoginCallBack {
void onLoginSuccess();
void onLoginFailed();
}
void login(String name, String password, OnLoginCallBack callBack);
}
- View層實現類LoginActivity
public class LoginActivity extends BaseMVPActivity<ILoginView, ILoginPresenter> implements ILoginView, View.OnClickListener {
private AppCompatEditText nameET;
private AppCompatEditText passwordET;
@Override
public int getLayoutId() {
return R.layout.activity_login;
}
@Override
public ILoginPresenter createPresenter() {
return new LoginPresenterImpl();
}
@Override
public void showEmptyInfo() {
Toast.makeText(this, "name or password is empty", Toast.LENGTH_LONG).show();
}
@Override
public void initView() {
nameET = (AppCompatEditText) findViewById(R.id.et_name);
passwordET = (AppCompatEditText) findViewById(R.id.et_password);
}
@Override
public void initListener() {
findViewById(R.id.btn_login).setOnClickListener(this);
findViewById(R.id.btn_clear).setOnClickListener(this);
}
@Override
public void clearTextView() {
nameET.setText("");
passwordET.setText("");
}
@Override
public void onLoginResult(boolean result) {
if (result) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(this, "Login false", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onClick(View view) {
String name = nameET.getText().toString();
String password = passwordET.getText().toString();
switch (view.getId()) {
case R.id.btn_clear:
getPresenter().clear();
break;
case R.id.btn_login:
getPresenter().login(name, password);
break;
}
}
}
1. Presenter實現類LoginPresenterImpl
public class LoginPresenterImpl extends ILoginPresenter implements ILoginModel.OnLoginCallBack {
private ILoginModel loginModel;
public LoginPresenterImpl() {
loginModel = new LoginModelImpl(this);
}
@Override
public void clear() {
view.clearTextView();
}
@Override
public void login(String name, String password) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)) {
view.showEmptyInfo();
}
loginModel.login(name, password, this);
}
@Override
public void onLoginSuccess() {
view.onLoginResult(true);
}
@Override
public void onLoginFailed() {
view.onLoginResult(false);
}
}
1. Model層LoginModelImpl
public class LoginModelImpl implements ILoginModel {
private ILoginPresenter presenter;
public LoginModelImpl(ILoginPresenter presenter) {
this.presenter = presenter;
}
@Override
public void login(String name, String password, OnLoginCallBack callBack) {
//模擬執行網路請求
if (name.equals("123") && password.equals("1234")) {
callBack.onLoginSuccess();
} else {
callBack.onLoginFailed();
}
}
}
三. MVP+data binding的開發模式
MVP中資料繫結setText和setListener等操作通過DataBinding的方式來實現
JavaBean繼承BaseObservable類,給layout佈局的data節點傳入javaBean物件
- MVP+DataBinding與MVVM的區別:
a. MVVM直接通過Databinding給Layout佈局傳入ViewModel物件,view層的事件處理和資料(JavaBean)獲取直接在viewModel中處理
b. MVP+DataBinding通過DataBinding給Layout佈局傳入ViewModel實體類,且該實體類物件是通過Presenter層獲取傳入到View層,View層的事件處理還是在View層處理