Android:MVC/MVP/MVVM 架構

1、架構

1、架構:將系統進行模塊/組件/角色的劃分,建立角色之間(數據結構/事件等)的通信機制。

2、需求

1、用戶輸入賬號名稱->點擊查詢賬戶信息->展示查詢成功失敗結果。
在這裏插入圖片描述

3、不使用架構

1、activity_architecture.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/etAccount"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:hint="請輸入查詢信息?" />

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/btnGetAccount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="獲取賬號信息" />

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/tvResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="--" />
</android.support.v7.widget.LinearLayoutCompat>

2、NormalActivity.java


public class NormalActivity extends AppCompatActivity implements View.OnClickListener {

    /**
     * 輸入查詢信息
     */
    private AppCompatEditText etAccount;
    /**
     * 展示查詢結果
     */
    private AppCompatTextView tvResult;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_architecture);
        initView();
    }

    /**
     * 初始化數據
     */
    private void initView() {
        etAccount = findViewById(R.id.etAccount);
        tvResult = findViewById(R.id.tvResult);
        findViewById(R.id.btnGetAccount).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnGetAccount:
                getAccountData(getAccount(), new ICallback() {
                    @Override
                    public void onSuccess(Account account) {
                        showSuccess(account);
                    }

                    @Override
                    public void onFailed() {
                        showFailed();
                    }
                });
                break;
        }
    }

    /**
     * 查詢獲取用戶數據
     *
     * @param accountName
     * @param callback
     */
    private void getAccountData(String accountName, ICallback callback) {
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess) {
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callback.onSuccess(account);
        } else {
            callback.onFailed();
        }
    }

    /**
     * 獲取用戶輸入信息
     *
     * @return
     */
    private String getAccount() {
        return etAccount.getText().toString();
    }

    /**
     * 獲取用戶信息成功
     *
     * @param account
     */
    private void showSuccess(Account account) {
        tvResult.setText("賬戶名:" + account.getName() + ",賬戶等級:" + account.getLevel());
    }

    /**
     * 獲取用戶信息失敗
     */
    private void showFailed() {
        tvResult.setText("獲取數據失敗!");
    }
}

4、MVC 模型

1、MVC (Model-View-Controller):模型-視圖-控制器。
2、Model:獲取數據(網絡請求,SQL等);View:layout、View控件;Controller:Activity、Fragment;數據通信:數據結構 和 事件。
在這裏插入圖片描述
3、優點:實現 Model 與 View 分離,降低代碼耦合。
4、缺點:Controller 與 View 難以解耦,項目越複雜 Controller 越臃腫。
5、例子:

  1. View:activity_architecture.xml 見 上文。
  2. Model:MvcModel
public class MvcModel {

    /**
     * 查詢獲取用戶數據
     *
     * @param accountName
     * @param callback
     */
    public void getAccountData(String accountName, ICallback callback) {
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess) {
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callback.onSuccess(account);
        } else {
            callback.onFailed();
        }
    }
}
  1. Controller
public class MvcActivity extends AppCompatActivity implements View.OnClickListener {

    /**
     * 輸入查詢信息
     */
    private AppCompatEditText etAccount;
    /**
     * 展示查詢結果
     */
    private AppCompatTextView tvResult;

    private MvcModel mMvcModel;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_architecture);
        initView();
    }

    /**
     * 初始化數據
     */
    private void initView() {
        etAccount = findViewById(R.id.etAccount);
        tvResult = findViewById(R.id.tvResult);
        findViewById(R.id.btnGetAccount).setOnClickListener(this);
        mMvcModel = new MvcModel();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnGetAccount:
                mMvcModel.getAccountData(getAccount(), new ICallback() {
                    @Override
                    public void onSuccess(Account account) {
                        showSuccess(account);
                    }

                    @Override
                    public void onFailed() {
                        showFailed();
                    }
                });
                break;
        }
    }

    /**
     * 獲取用戶輸入信息
     *
     * @return
     */
    private String getAccount() {
        return etAccount.getText().toString();
    }

    /**
     * 獲取用戶信息成功
     *
     * @param account
     */
    private void showSuccess(Account account) {
        tvResult.setText("賬戶名:" + account.getName() + ",賬戶等級:" + account.getLevel());
    }

    /**
     * 獲取用戶信息失敗
     */
    private void showFailed() {
        tvResult.setText("獲取數據失敗!");
    }
}
5、MVP 模型

1、MVP (Model-View-Presenter):模型-視圖-控制器。
在這裏插入圖片描述
2、MVP 與 MVC 差異:Modle 與 View 不直接通信,通過 Presenter 實現通信;Activity 功能簡化,主要負責 View 層的工作。
3、優點:解決 MVC 中 Controller 與 View 耦合的缺點,職責劃分明顯,更易於維護。
4、缺點:接口數量多,項目越複雜 Presenter 層越臃腫。
5、例子:

  1. Model
public class MvpModel {

    /**
     * 查詢獲取用戶數據
     *
     * @param accountName
     * @param callback
     */
    public void getAccountData(String accountName, ICallback callback) {
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess) {
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callback.onSuccess(account);
        } else {
            callback.onFailed();
        }
    }
}
  1. Presenter
public class MvpPresenter {
    private IMvpView mView;
    private MvpModel mModel;

    public MvpPresenter(IMvpView view) {
        this.mView = view;
        mModel = new MvpModel();
    }

    public void getAccountData(String accountName) {
        mModel.getAccountData(accountName, new ICallback() {
            @Override
            public void onSuccess(Account account) {
                mView.showSuccess(account);
            }

            @Override
            public void onFailed() {
                mView.showFailed();
            }
        });
    }
}
  1. View:activity_architecture.xml 見 上文。
public interface IMvpView {
    /**
     * 獲取用戶輸入信息
     * @return
     */
    String getAccount();

    /**
     * 獲取用戶信息成功
     * @param account
     */
    void showSuccess(Account account);

    /**
     * 獲取用戶信息失敗
     */
    void showFailed();
}

public class MvpActivity extends AppCompatActivity implements View.OnClickListener, IMvpView {

    /**
     * 輸入查詢信息
     */
    private AppCompatEditText etAccount;
    /**
     * 展示查詢結果
     */
    private AppCompatTextView tvResult;

    private MvpPresenter mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_architecture);
        initView();
    }

    /**
     * 初始化數據
     */
    private void initView() {
        etAccount = findViewById(R.id.etAccount);
        tvResult = findViewById(R.id.tvResult);
        findViewById(R.id.btnGetAccount).setOnClickListener(this);
        mPresenter = new MvpPresenter(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnGetAccount:
                mPresenter.getAccountData(getAccount());
                break;
        }
    }

    /**
     * 獲取用戶輸入信息
     *
     * @return
     */
    @Override
    public String getAccount() {
        return etAccount.getText().toString();
    }

    /**
     * 獲取用戶信息成功
     *
     * @param account
     */
    @Override
    public void showSuccess(Account account) {
        tvResult.setText("賬戶名:" + account.getName() + ",賬戶等級:" + account.getLevel());
    }

    /**
     * 獲取用戶信息失敗
     */
    @Override
    public void showFailed() {
        tvResult.setText("獲取數據失敗!");
    }
}
6、dataBinding 使用

1、DataBinding:谷歌推出的數據綁定框架。
2、使用:

  1. 啓用 DataBinding
// build.gradle
android {
    // 1.啓用dataBinding
    dataBinding{
        enabled = true
    }
}
  1. 佈局轉爲 DataBinding 佈局:alt+enter->Convert to data binding layout。
  2. 數據綁定
7、MVVM 模型

1、MVVM (Model-View-ViewModel):模型-視圖-視圖模型。實現數據視圖綁定(DataBinding),數據變化視圖自定更新,視圖變化數據也會自動更新。
在這裏插入圖片描述
2、MVVM 優點:實現數據和視圖的雙向綁定簡化代碼;減少接口數量;不需要 findViewById 操作。
3、MVVM 缺點:bug 難調試,dataBinding 編譯不及時。
4、例子:

  1. Model
public class MvvmModel {

    /**
     * 查詢獲取用戶數據
     *
     * @param accountName
     * @param callback
     */
    public void getAccountData(String accountName, ICallback callback) {
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess) {
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callback.onSuccess(account);
        } else {
            callback.onFailed();
        }
    }
}
  1. View
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="viewModel"
            type="com.strugglelin.architecture.mvvm.MvvmViewModel" />
    </data>

    <android.support.v7.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <android.support.v7.widget.AppCompatEditText
            android:id="@+id/etAccount"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:hint="請輸入查詢信息?"
            android:text="@={viewModel.userInput}" />

        <android.support.v7.widget.AppCompatButton
            android:id="@+id/btnGetAccount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{viewModel.getAccountData}"
            android:text="獲取賬號信息" />

        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/tvResult"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{viewModel.result}" />
    </android.support.v7.widget.LinearLayoutCompat>
</layout>
  1. ViewModel
public class MvvmViewModel extends BaseObservable {

    private Application application;
    private MvvmModel model;
    private ActivityMvvmBinding binding;
    private String result;
    private String userInput;

    @Bindable
    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
        notifyPropertyChanged(BR.result);
    }

    @Bindable
    public String getUserInput() {
        return userInput;
    }

    public void setUserInput(String userInput) {
        this.userInput = userInput;
        notifyPropertyChanged(BR.userInput);
    }

    public MvvmViewModel(Application application) {
        this.application = application;
        model = new MvvmModel();
    }

    public MvvmViewModel(Application application, ActivityMvvmBinding binding) {
        this.application = application;
        model = new MvvmModel();
        this.binding = binding;
    }

    public void getAccountData(View view) {
//        final String accountName = binding.etAccount.getText().toString();
        model.getAccountData(userInput, new ICallback() {
            @Override
            public void onSuccess(Account account) {
                String info = account.getName() + "|" + account.getLevel();
                setResult(info);
            }

            @Override
            public void onFailed() {
                setResult("獲取數據失敗!");
            }
        });
    }
}
public class MvvmActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMvvmBinding binding;
        binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
        MvvmViewModel model = new MvvmViewModel(getApplication());
        binding.setViewModel(model);
    }
}

注:TheArchitecture Demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章