問題提出:如何優雅地分離出應用程序的狀態、用戶交互和數據表現?如何通過框架體現工程的高性能、高靈活性、高響應性?
MVC定義:model、view、controller三者的有機組合,分別表示:模型、視圖和控制。
這個模式認為:程序不論簡單還是復雜,從結構上來看,都可以分為三個層次。
下圖展示了MVC程序框架在Android應用程序中的使用,以及各個層次使用哪些組件擔當:

1)最上面一層,是直接面向於最終用戶的“視圖層”(View)。它是提供給用戶的操作界面,是程序的外殼。界面就是各種UI組件(XML布局或者Java自定義控件對象)。只負責展示數據,同時接收控制器傳過來的結果。
2)最底下的一層,是核心的“數據層”(Model),也就是程序需要操作的數據或信息(系統中的業務邏輯部分)。通常是數據庫SQLite、網絡請求的JSON、本地XML或者Java對象數據。它代表了一些實體類,用來描述業務邏輯怎么組合,同時也為數據定義業務規則;
3)中間的一層,就是“控制層”(controller),負責根據用戶從“視圖層”輸入的指令,選取“數據層”中的數據,然后對其進行相應的操作,產生最終的結果(可以分派用戶的請求並選擇恰當的視圖以用於顯示,同時也可以解釋用戶的數據並將它們映射為模型層可執行的操作)。控制器是與應用程序相關聯的動作集合,負責處理待響應的請求。通過界面響應用戶輸入,通過模型層處理數據,最后返回結果給界面。控制器扮演着模型和界面的粘合劑角色。
抽象一點,上述模型可以抽象為下述結果:

展示了從Activity接收用於點擊輸入,控制器響應用戶輸入並發起Internet請求數據(網絡請求),響應結果經過模型層轉換,最后控制器取到模型層數據並通知界面進行刷新。
更加簡化的MVC模型如下:

或者是下述結果:

在Android中,View和Model也是有關聯的,從而抽象為下述圖:

上述的三個層次是緊密聯系,且是相互獨立的,每一層的變化不影響其他層次。每一層都對外提供接口,供上面一層調用。軟件因而實現模塊化,修改外觀或者變更數據都不用修改其他層次,大大方便了維護和升級。

一個邏輯模型可以對於多種視圖模型,比如一批統計數據可以分別用柱狀圖、餅狀圖來顯示結果;一種視圖模型也可以對應多種邏輯模型。使用MVC的目的就是將M和V的實現代碼分離,從而使同一個程序可以使用不同的表現形式,而Controller存在的目的則是確保M改變,V應該同步更新。
使用計算器這個例子作為實例進行分析:外部的按鈕和上面的顯示條,就是“視圖層”;需要運算的數字就是“數據層”;執行加減乘除的內部運算步驟就是“控制層”。每一層執行不同的功能,整個程序的結構很清晰。
MVC的好處在於:從用戶的角度出發,用戶可以根據自己的需求,選擇自己合適瀏覽數據的方式。比如說,對於一篇在線文檔,用戶可以選擇以HTML網頁的方式閱讀,也可以選擇以pdf的方式閱讀。從開發者的角度來看,MVC把應用程序的邏輯層與界面完全分開。

Android應用程序中,MVC框架是如何實現的?都充當什么角色?
1. View接受用戶的交互請求;
2. View將請求轉交給Controller;
3. Controller(用戶做的動作比如:update數據,刪除指定名字的學生等等)操作Model進行數據更新(根據用戶指示,執行底層的數據動作等等);
4. 數據更新之后,Model通知View數據變化;
5. View顯示更新之后的數據;
M層適合做一些業務邏輯處理,比如數據庫存取操作、網絡操作、復雜的算法等耗時操作;
V層顯示數據部分,XML布局可以視為是V層,顯示Model層的數據結果;
C層適合使用Activity擔當,Android中Activity用於處理用戶交互問題(發起業務請求),讀取用戶輸入(等待業務處理結果),響應用戶點擊等等事件。
MainActivity.java代碼如下:
package com.demo.controller;
import static com.demo.controller.ControllerProtocol.C_DATA;
import static com.demo.controller.ControllerProtocol.C_QUIT;
import static com.demo.controller.ControllerProtocol.C_UPDATE_FINISHED;
import static com.demo.controller.ControllerProtocol.C_UPDATE_STARTED;
import static com.demo.controller.ControllerProtocol.V_REQUEST_DATA;
import static com.demo.controller.ControllerProtocol.V_REQUEST_QUIT;
import static com.demo.controller.ControllerProtocol.V_REQUEST_UPDATE;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.demo.R;
import com.demo.model.Model;
import com.demo.model.ModelData;
import com.demo.utils.LogUtil;
public class MvcActivity extends Activity implements Callback,
View.OnClickListener {
private static final String TAG = MvcActivity.class.getSimpleName();
private Controller controller;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.update).setOnClickListener(this);
findViewById(R.id.quit).setOnClickListener(this);
// 初始化層次結構中的交互
controller = new Controller(new Model());
// 使用MvcActivity所在的主線程初始化outBox中的Handler
controller.addOutboxHandler(new Handler(MvcActivity.this));
// Controller層發送請求數據的Message
controller.getInboxHandler().sendEmptyMessage(V_REQUEST_DATA);
}
@Override
public void onClick(View v) {
// 接收用戶輸入
switch (v.getId()) {
case R.id.update:
LogUtil.d(TAG, "User click input: R.id.update");
// 接收用戶輸入並得到Controller層響應,Controller層發送請求數據的Message
controller.getInboxHandler().sendEmptyMessage(V_REQUEST_UPDATE);
break;
case R.id.quit:
LogUtil.d(TAG, "User click input: R.id.quit");
// 接收用戶輸入並得到Controller層響應,Controller層發送請求數據的Message
controller.getInboxHandler().sendEmptyMessage(V_REQUEST_QUIT);
break;
}
}
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "Received message: " + msg);
switch (msg.what) {
case C_QUIT:
// 接收Controller層輸入,准備退出應用
onQuit();
return true;
case C_DATA:
// 將數據顯示到View層
onData((ModelData) msg.obj);
return true;
case C_UPDATE_STARTED:
// (狀態)正在后台請求數據
onUpdateStarted();
return true;
case C_UPDATE_FINISHED:
// (狀態)后台請求數據結束,准備顯示
onUpdateFinished();
return true;
}
return false;
}
@Override
protected void onDestroy() {
try {
controller.dispose();
} catch (Throwable t) {
LogUtil.d(TAG, "Failed to destroy the controller");
}
super.onDestroy();
}
/**
* <功能描述> Controller層做出update響應,更新View層
*
* @return void [返回類型說明]
*/
private void onQuit() {
LogUtil.d(TAG, "Activity quitting");
finish();
}
/**
* <功能描述> 從Controller層傳遞過來的Message,表明獲取到返回的數據,更新View
*
* @param data [參數說明]
* @return void [返回類型說明]
*/
private void onData(ModelData data) {
LogUtil.d(TAG, "onData::running...");
TextView dataView = (TextView) findViewById(R.id.data_view);
dataView.setText("The answer is " + data.getAnswer());
}
/**
* <功能描述> 開始Update數據顯示ProgressBar
*
* @return void [返回類型說明]
*/
private void onUpdateStarted() {
LogUtil.d(TAG, "onUpdateStarted::running...");
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.VISIBLE);
}
/**
* <功能描述> Update數據過程結束后,ProgressBar消失,顯示數據
*
* @return void [返回類型說明]
*/
private void onUpdateFinished() {
LogUtil.d(TAG, "onUpdateFinished::running...");
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.GONE);
controller.getInboxHandler().sendEmptyMessage(V_REQUEST_DATA);
}
}
Controller.java代碼如下:
package com.demo.controller;
import static com.demo.controller.ControllerProtocol.C_QUIT;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import com.demo.model.Model;
import com.demo.utils.LogUtil;
import java.util.ArrayList;
import java.util.List;
public class Controller {
private static final String TAG = Controller.class.getSimpleName();
private final Model model;
// 使用HandlerThread、Handler、Message機制實現不同層的消息通信
// inBox:用於接收從View層發送的Message
private final HandlerThread inboxHandlerThread;
private final Handler inboxHandler;
// outBox:用於Controller給View發送Message
private final List<Handler> outboxHandlers = new ArrayList<Handler>();
// 將消息處理委托給ControllerState,不在Controller中處理Message
private ControllerState state;
/**
* <默認構造函數> Controller層初始化
*/
public Controller(Model model) {
this.model = model;
// Handler就存在於該Thread子線程(也就是工作線程)中
inboxHandlerThread = new HandlerThread("Controller Inbox");
inboxHandlerThread.start();
// HandlerThread的getLooper()獲取到Handler實例
inboxHandler = new Handler(inboxHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Controller.this.handleMessage(msg);
}
};
// 初始化ControllerState,准備接受Message
this.state = new ReadyState(this);
}
// 處理從View層傳遞過來的Message
private void handleMessage(Message msg) {
LogUtil.d(TAG, "handleMessage::Received message...msg.what=" + msg.what);
// 把消息處理委托給它的 ControllerState
if (!state.handleMessage(msg)) {
LogUtil.d(TAG, "Unknown message: " + msg);
}
}
/**
* <功能描述> inboxHandlerThread退出
*
* @return void [返回類型說明]
*/
public final void dispose() {
inboxHandlerThread.getLooper().quit();
}
/**
* <功能描述>獲取inBox的Handler實例,並返回該實例
*
* @return [參數說明]
* @return Handler [返回類型說明]
*/
public final Handler getInboxHandler() {
return inboxHandler;
}
/**
* <功能描述> 增加Handler到outBox中;outBox用於Controller傳送Message到View層
*
* @param handler [參數說明]
* @return void [返回類型說明]
*/
public final void addOutboxHandler(Handler handler) {
outboxHandlers.add(handler);
}
/**
* <功能描述> 從outBox移除Handler
*
* @param handler [參數說明]
* @return void [返回類型說明]
*/
public final void removeOutboxHandler(Handler handler) {
outboxHandlers.remove(handler);
}
/**
* <功能描述> 更新Controller的狀態,ReadyState和UpdatingState之間的切換
*
* @param newState [參數說明]
* @return void [返回類型說明]
*/
final void changeState(ControllerState newState) {
LogUtil.d(TAG,
String.format("Changing state from %s to %s", state, newState));
state = newState;
}
/**
* <功能描述> Controller層向View層發送Message
*
* @param what
* @param arg1
* @param arg2
* @param obj [參數說明]
* @return void [返回類型說明]
*/
final void notifyOutboxHandlers(int what, int arg1, int arg2, Object obj) {
LogUtil.d(TAG, "notifyOutboxHandlers::running...what=" + what);
if (outboxHandlers.isEmpty()) {
LogUtil.d(TAG, String.format(
"No outbox handler to handle outgoing message (%d)", what));
} else {
for (Handler handler : outboxHandlers) {
Message msg = Message.obtain(handler, what, arg1, arg2, obj);
msg.sendToTarget();
}
}
}
/**
* <功能描述> 獲取到Model層
*
* @return [參數說明]
* @return Model [返回類型說明]
*/
final Model getModel() {
return model;
}
/**
* <功能描述> 接收用戶輸入,准備退出應用
*
* @return void [返回類型說明]
*/
final void quit() {
notifyOutboxHandlers(C_QUIT, 0, 0, null);
}
}
ControllerState.java代碼如下:
package com.demo.controller;
import android.os.Message;
/**
* <功能描述> 將Controller層的消息處理邏輯轉交給ControllerState處理;ControllerState有兩個實現類:
* ReadyState和UpdatingState
*
* @author Administrator
*/
public interface ControllerState {
boolean handleMessage(Message msg);
}
ReadyState.java代碼如下:
package com.demo.controller;
import android.os.Message;
import com.demo.utils.LogUtil;
import static com.demo.controller.ControllerProtocol.*;
/**
* <功能描述> 數據更新的狀態之一:准備階段,最前面的狀態
*
* @author Administrator
*/
final class ReadyState implements ControllerState {
private static final String TAG = ReadyState.class.getSimpleName();
private final Controller controller;
public ReadyState(Controller controller) {
this.controller = controller;
}
@Override
public final boolean handleMessage(Message msg) {
LogUtil.d(TAG, "handleMessage::running...msg.what=" + msg.what);
switch (msg.what) {
case V_REQUEST_QUIT:
// 從View層獲取到的Quite消息
onRequestQuit();
return true;
case V_REQUEST_UPDATE:
// 從View層獲取到的Update的消息
onRequestUpdate();
return true;
case V_REQUEST_DATA:
// 從View層獲取到的更新數據的消息
onRequestData();
return true;
}
return false;
}
/**
* <功能描述> 請求數據
*
* @return void [返回類型說明]
*/
private void onRequestData() {
LogUtil.d(TAG, "onRequestData::running...");
controller.notifyOutboxHandlers(C_DATA, 0, 0, controller.getModel()
.getData());
}
/**
* <功能描述> 請求更新數據,並更改Controller的狀態
*
* @return void [返回類型說明]
*/
private void onRequestUpdate() {
LogUtil.d(TAG, "onRequestUpdate::running...");
// 狀態返回給Controller層,並將狀態改變為UpdatingState
controller.changeState(new UpdatingState(controller));
}
private void onRequestQuit() {
LogUtil.d(TAG, "onRequestQuit::running...");
controller.quit();
}
}
UpdatingState.java代碼如下:
package com.demo.controller;
import static com.demo.controller.ControllerProtocol.C_UPDATE_FINISHED;
import static com.demo.controller.ControllerProtocol.C_UPDATE_STARTED;
import static com.demo.controller.ControllerProtocol.V_REQUEST_QUIT;
import android.os.Message;
import com.demo.utils.LogUtil;
/**
* <功能描述> 數據更新的狀態之一:正在更新階段
*
* @author Administrator
*/
final class UpdatingState implements ControllerState {
private static final String TAG = UpdatingState.class.getSimpleName();
private final Controller controller;
private final Thread updateThread;
public UpdatingState(Controller controller) {
this.controller = controller;
// 新建一個Thread工作線程
updateThread = new Thread("Model Update") {
@Override
public void run() {
Controller controller = UpdatingState.this.controller;
try {
// 在工作線程中執行數據請求(抽象為相對耗時的操作),可為其他:數據庫操作
controller.getModel().updateData();
} catch (Throwable t) {
LogUtil.d(TAG, "Error in the update thread");
} finally {
// controller.getModel().updateData()執行完后,反饋數據給Controller層
notifyControllerOfCompletion();
}
}
};
updateThread.start();
// Controller層向View層發送Message,開始更新數據
controller.notifyOutboxHandlers(C_UPDATE_STARTED, 0, 0, null);
}
@Override
public boolean handleMessage(Message msg) {
LogUtil.d(TAG, "handleMessage::msg.what=" + msg.what);
switch (msg.what) {
case V_REQUEST_QUIT:
onRequestQuit();
return true;
}
return false;
}
/**
* <功能描述> 數據獲取到后,最終會反饋給Controller層
*
* @return void [返回類型說明]
*/
private void notifyControllerOfCompletion() {
LogUtil.d(TAG, "notifyControllerOfCompletion::starting...");
controller.getInboxHandler().post(new Runnable() {
@Override
public void run() {
// 將狀態改變為ReadyState
controller.changeState(new ReadyState(controller));
// 並通知結束更新
controller.notifyOutboxHandlers(C_UPDATE_FINISHED, 0, 0, null);
}
});
}
private void onRequestQuit() {
LogUtil.d(TAG, "onRequestQuit::starting...");
updateThread.interrupt();
controller.quit();
}
}
ControllerProtocal.java代碼如下:
package com.demo.controller;
public interface ControllerProtocol {
// 從View層傳遞的Message
int V_REQUEST_QUIT = 101;
int V_REQUEST_UPDATE = 102;
int V_REQUEST_DATA = 103;
// 從Controller層傳遞的Message
int C_QUIT = 201;
int C_UPDATE_STARTED = 202;
int C_UPDATE_FINISHED = 203;
int C_DATA = 204; // obj = (ModelData) data
}
Model.java代碼如下:
package com.demo.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.os.SystemClock;
import com.demo.utils.LogUtil;
/**
* <功能描述> 專指Model層;使用ThreadSafe指示是線程安全的
*
* @author Administrator
*/
public class Model {
private static final String TAG = Model.class.getSimpleName();
public interface Listener {
void onModelStateUpdated(Model model);
}
// Model模型中包含有ModelData
private ModelData data = new ModelData(0);
private final List<Listener> listeners = new ArrayList<Listener>();
public Model() {
LogUtil.d(TAG, "Model constructer..");
}
public final ModelData getData() {
synchronized (this) {
return data;
}
}
/**
* <功能描述> 更新數據
*
* @return void [返回類型說明]
*/
public final void updateData() {
// 可能是請求服務器數據,執行繁重的計算
SystemClock.sleep(3000);
ModelData newData = new ModelData(new Random().nextInt(10) + 1);
synchronized (this) {
data = newData;
}
synchronized (listeners) {
for (Listener listener : listeners) {
listener.onModelStateUpdated(this);
}
}
}
/**
* <功能描述>增加監聽器
*
* @param listener [參數說明]
* @return void [返回類型說明]
*/
public final void addListener(Listener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
/**
* <功能描述>移除監聽器
*
* @param listener [參數說明]
* @return void [返回類型說明]
*/
public final void removeListener(Listener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
}
ModelData.java代碼如下:
package com.demo.model;
import com.demo.utils.LogUtil;
import java.io.Serializable;
/**
* <功能描述> Model層中的數據,指示數據層的狀態;Immutable指示是不變的
*
* @author Administrator
*/
public final class ModelData implements Serializable {
private static final String TAG = ModelData.class.getSimpleName();
private static final long serialVersionUID = 1L;
private final int answer;
public ModelData(int answer) {
LogUtil.d(TAG, "ModelData::answer=" + answer);
this.answer = answer;
}
public final int getAnswer() {
LogUtil.d(TAG, "getAnswer::answer=" + answer);
return answer;
}
}
View代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.demo.controller.MvcActivity" > <TextView android:id="@+id/data_view" style="@android:style/TextAppearance.Large" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:gravity="center" android:text="" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:weightSum="2.0" > <Button android:id="@+id/update" android:layout_width="0px" android:layout_height="wrap_content" android:layout_weight="1.0" android:text="Update" /> <Button android:id="@+id/quit" android:layout_width="0px" android:layout_height="wrap_content" android:layout_weight="1.0" android:text="Quit" /> </LinearLayout> <ProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:indeterminate="true" android:visibility="gone" /> </LinearLayout>
更加詳細的MPV模型解析:

