為什么要學習MVC
需求(查詢用戶賬號信息):
用戶輸入賬號,點擊按鈕可進行查詢賬號信息,如果查詢數(shù)據(jù)成功,則將數(shù)據(jù)展示在界面上;如果查詢數(shù)據(jù)失敗,則在界面上提示獲取數(shù)據(jù)失敗。
不實用框架實現(xiàn)需求
創(chuàng)建一個Activity,實現(xiàn)它的所有功能(獲取用戶輸入信息,展示獲取信息成功界面,展示獲取信息失敗界面,查詢用戶數(shù)據(jù),業(yè)務邏輯)。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText edittext;
private Button button;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
}
@Override
public void onClick(View v) {
String userInput = getUserInput();
getAccountData(userInput, new MCallBack() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFail() {
showFailPage();
}
});
}
//獲取用戶輸入信息
private String getUserInput() {
return edittext.getText().toString().trim();
}
//展示獲取信息成功界面
private void showSuccessPage(Account account) {
text.setText("用戶賬號:" + account.getName() + "|" + "用戶等級:" + account.getLevel());
}
//展示獲取信息失敗界面
private void showFailPage() {
text.setText("獲取數(shù)據(jù)失敗");
}
//查詢用戶數(shù)據(jù)
private void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
由上述代碼可以發(fā)現(xiàn),MainActivity承載了太多的功能,既要實現(xiàn)方法,又要承擔邏輯,這樣當以后功能越來越多的時候,這個界面的代碼就會越來越多,越來越臃腫。
MVC模型簡介
MVC的全名是Model View Controller,即模型(Model)-視圖(View)-控制器(Controller)。
Controller:Activity,Fragment
View:layout,View控件
Controller:數(shù)據(jù)處理(網(wǎng)絡請求,SQL等)

使用MVC實現(xiàn)需求
MVCActivity(C層):業(yè)務邏輯處理,獲取用戶輸入,展示成功界面,展示失敗界面
MVCModel(M層):查詢賬號數(shù)據(jù)
View(V層):layout
1.將數(shù)據(jù)的獲取和界面的展示分離(將查詢賬號數(shù)據(jù)從Activity中分離到Model中即可)
2.解決各層之間的通信問題(Activity通知Model獲取數(shù)據(jù),Model通知Activity更新界面)
public class MVCActivity extends AppCompatActivity implements View.OnClickListener {
private EditText edittext;
private Button button;
private TextView text;
private MVCModel mvcModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
mvcModel = new MVCModel();
}
@Override
public void onClick(View v) {
mvcModel.getAccountData(getUserInput(), new MCallBack() {
@Override
public void onSuccess(Account account) {
showSuccessPage(account);
}
@Override
public void onFail() {
showFailPage();
}
});
}
//獲取用戶輸入信息
private String getUserInput() {
return edittext.getText().toString().trim();
}
//展示獲取信息成功界面
private void showSuccessPage(Account account) {
text.setText("用戶賬號:" + account.getName() + "|" + "用戶等級:" + account.getLevel());
}
//展示獲取信息失敗界面
private void showFailPage() {
text.setText("獲取數(shù)據(jù)失敗");
}
}
public class MVCModel {
//查詢用戶數(shù)據(jù)
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
MVC優(yōu)缺點
優(yōu)點:一定程度上實現(xiàn)了Model與View的分離,降低了代碼的耦合性。
缺點:Controller與View難以完全解耦,并且隨著項目復雜度的提升,因為Controller還承擔部分業(yè)務邏輯,所以Controller將越來越臃腫。
MVP模型簡介
MVP即Model_View_Presenter模型

MVP與MVC的差別
1.Model與View不再直接進行通信,而是通過中間層Presenter來實現(xiàn)。
- Activity的功能被簡化,不再充當控制器,主要負責View層面的工作。
MVP代碼實戰(zhàn)

使用MVP實現(xiàn)需求
- MVPActivity負責提供View層面的功能(采用實現(xiàn)接口的方式)
2.MVPModel負責提供數(shù)據(jù)方面的功能
3.Model與View不再直接通信,通過Presenter來實現(xiàn)
public class MVPActivity extends AppCompatActivity implements View.OnClickListener, IMVPView {
private EditText edittext;
private Button button;
private TextView text;
private MVPPresenter mvpPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
init();
}
private void init() {
edittext = findViewById(R.id.edittext);
button = findViewById(R.id.button);
button.setOnClickListener(this);
text = findViewById(R.id.text);
mvpPresenter = new MVPPresenter(this);
}
@Override
public void onClick(View v) {
mvpPresenter.getData(getUserInput());
}
@Override
public String getUserInput() {
return edittext.getText().toString().trim();
}
@Override
public void showSuccessPage(Account account) {
text.setText("用戶賬號:" + account.getName() + "|" + "用戶等級:" + account.getLevel());
}
@Override
public void showFailPage() {
text.setText("獲取數(shù)據(jù)失敗");
}
}
public interface IMVPView {
String getUserInput();
void showSuccessPage(Account account);
void showFailPage();
}
public class MVPModel {
//查詢用戶數(shù)據(jù)
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}
public class MVPPresenter {
private IMVPView imvpView;
private MVPModel mvpModel;
public MVPPresenter(IMVPView imvpView) {
this.imvpView = imvpView;
mvpModel = new MVPModel();
}
public void getData(String accountName) {
mvpModel.getAccountData(accountName, new MCallBack() {
@Override
public void onSuccess(Account account) {
imvpView.showSuccessPage(account);
}
@Override
public void onFail() {
imvpView.showFailPage();
}
});
}
}
MVP優(yōu)缺點
優(yōu)點:解決了MVC中Controller與View過度耦合的缺點,職責劃分明顯,更加易于維護。
缺點:接口數(shù)量多,項目復雜度升高。隨著項目復雜度的提升,Presenter層將越來越臃腫。
使用MVP的建議
1.接口規(guī)范化(封裝父類接口以減少接口的使用量)
2.使用第三方插件自動生成MVP代碼
3.對于一些簡單的界面,可以選擇不使用框架
4.根據(jù)項目復雜程度,部分模塊可以選擇不使用接口
MVVM模型簡介

MVVM是Model-View-ViewModel的簡寫,MVVM在MVP的基礎上實現(xiàn)了數(shù)據(jù)視圖的綁定(DataBinding),當數(shù)據(jù)變化時,視圖會自動更新;反之,當視圖發(fā)生變化時,數(shù)據(jù)也會自動更新。
1.減少了接口數(shù)量
2.告別繁瑣findViewById操作
DataBinding是什么
DataBinding是谷歌官方發(fā)布的一個實現(xiàn)數(shù)據(jù)綁定的框架(實現(xiàn)數(shù)據(jù)與視圖雙向綁定),DataBinding可以幫助我們在安卓中更好的實現(xiàn)MVVM模式。
DataBinding使用步驟
1.啟用DataBinding
2.修改布局文件為DataBinding布局
3.數(shù)據(jù)綁定
使用MVVM實現(xiàn)需求

1.提供View,ViewModel以及Model三層
2.將布局修改為DataBinding布局
- View與ViewModel之間通過DataBinding進行通信
- 獲取數(shù)據(jù)并展示在界面上
public class MVVMActivity extends AppCompatActivity {
private MVVMViewModel mvvmViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
mvvmViewModel = new MVVMViewModel(getApplication(),binding);
binding.setViewModel(mvvmViewModel);
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.test.myapplication.mvvm.MVVMViewModel"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/edittext"
android:text="@={viewModel.userInput}"
android:hint="請輸入要查詢的賬號"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_gravity="center"
android:id="@+id/button"
android:text="獲取賬號信息"
android:onClick="@{viewModel.getData}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text"
android:layout_marginTop="50dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.result}"
android:hint="賬號信息未獲取" />
</LinearLayout>
</layout>
public class MVVMViewModel extends BaseObservable {
private String result;
private String userInput;
private MVVMModel model;
private ActivityMvvmBinding binding;
//一般需要傳入Application對象,方便在ViewModel中使用application
//比如sharepreferences
public MVVMViewModel(Application application) {
model = new MVVMModel();
}
public MVVMViewModel(Application application, ActivityMvvmBinding binding) {
model = new MVVMModel();
this.binding = binding;
}
public void getData(View view) {
model.getAccountData(userInput, new MCallBack() {
@Override
public void onSuccess(Account account) {
String info = "用戶賬號:" + account.getName() + "|" + "用戶等級:" + account.getLevel();
setResult(info);
}
@Override
public void onFail() {
setResult("獲取數(shù)據(jù)失敗");
}
});
}
@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 class MVVMModel {
//查詢用戶數(shù)據(jù)
public void getAccountData(String accountName, MCallBack mCallBack) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
mCallBack.onSuccess(account);
} else {
mCallBack.onFail();
}
}
}