1. 程式人生 > >Android Mvp+DataBinding架構模式詳解

Android Mvp+DataBinding架構模式詳解

MVP模式的使用

一. MVC與MVP設計模式的區別

  1. 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層相互可知,兩者之間存在耦合
  2. 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;
          }
      }
  1. 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();
    }
  1. 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);
       }
  1. View層介面ILoginView:
    public interface ILoginView {
        void clearTextView();

        void onLoginResult(boolean result);

        void showEmptyInfo();
    }
  1. Presenter層介面ILoginPresenter
      public abstract class ILoginPresenter extends BasePresenter<ILoginView>{
           public abstract void clear();

           public abstract void login(String name, String password);
       }
  1. Model層介面ILoginModel
   public interface ILoginModel {
        public interface OnLoginCallBack {
            void onLoginSuccess();

            void onLoginFailed();
        }

        void login(String name, String password, OnLoginCallBack callBack);
    }
  1. 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的開發模式

  1. MVP中資料繫結setText和setListener等操作通過DataBinding的方式來實現

  2. JavaBean繼承BaseObservable類,給layout佈局的data節點傳入javaBean物件

  3. MVP+DataBinding與MVVM的區別:
    a. MVVM直接通過Databinding給Layout佈局傳入ViewModel物件,view層的事件處理和資料(JavaBean)獲取直接在viewModel中處理
    b. MVP+DataBinding通過DataBinding給Layout佈局傳入ViewModel實體類,且該實體類物件是通過Presenter層獲取傳入到View層,View層的事件處理還是在View層處理