MCV model view controller 模型-視圖-控制寫
M層:適合做一些業務邏輯處理,比如數據庫存取操作,網絡操作,復雜的算法,耗時的任務等都在model層處理。
V層:應用層中處理數據顯示的部分,XML布局可以視為V層,顯示Model層的數據結果。
C層:在Android中,Activity處理用戶交互問題,因此可以認為Activity是控制器,Activity讀取V視圖層的數據(eg.讀取當前EditText控件的數據),控制用戶輸入(eg.EditText控件數據的輸入),並向Model發送數據請求(eg.發起網絡請求等)。
首先來看一下MVC模式的例子,調用網絡接口————藏頭詩生成接口
xml布局如下:

1 xmlns:tools="http://schemas.android.com/tools" 2 android:id="@+id/activity_main" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 tools:context="com.example.lesson_mvc_cangtoushi.ui.MainActivity"> 7 8 <RadioGroup 9 android:id="@+id/rg_57" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:orientation="horizontal"> 13 14 <RadioButton 15 android:id="@+id/rb_5" 16 android:layout_width="0dp" 17 android:layout_height="wrap_content" 18 android:layout_weight="1" 19 android:gravity="center" 20 android:text="五言詩" /> 21 22 <RadioButton 23 android:id="@+id/rb_7" 24 android:layout_width="0dp" 25 android:layout_height="wrap_content" 26 android:layout_weight="1" 27 android:gravity="center" 28 android:text="七言詩" /> 29 </RadioGroup> 30 31 <RadioGroup 32 android:id="@+id/rg_ct" 33 android:layout_width="match_parent" 34 android:layout_height="wrap_content" 35 android:orientation="horizontal"> 36 37 <RadioButton 38 android:id="@+id/rb_ct" 39 android:layout_width="0dp" 40 android:layout_height="wrap_content" 41 android:layout_weight="1" 42 android:gravity="center" 43 android:text="藏頭" /> 44 45 <RadioButton 46 android:id="@+id/rb_cw" 47 android:layout_width="0dp" 48 android:layout_height="wrap_content" 49 android:layout_weight="1" 50 android:gravity="center" 51 android:text="藏尾" /> 52 53 <RadioButton 54 android:id="@+id/rb_cz" 55 android:layout_width="0dp" 56 android:layout_height="wrap_content" 57 android:layout_weight="1" 58 android:gravity="center" 59 android:text="藏中" /> 60 61 <RadioButton 62 android:id="@+id/rb_dz" 63 android:layout_width="0dp" 64 android:layout_height="wrap_content" 65 android:layout_weight="1" 66 android:gravity="center" 67 android:text="遞增" /> 68 69 <RadioButton 70 android:id="@+id/rb_dj" 71 android:layout_width="0dp" 72 android:layout_height="wrap_content" 73 android:layout_weight="1" 74 android:gravity="center" 75 android:text="遞減"/> 76 77 </RadioGroup> 78 79 <RadioGroup 80 android:id="@+id/rg_yy" 81 android:layout_width="match_parent" 82 android:layout_height="wrap_content" 83 android:orientation="horizontal"> 84 85 <RadioButton 86 android:id="@+id/rb_1y" 87 android:layout_width="0dp" 88 android:layout_height="wrap_content" 89 android:layout_weight="1" 90 android:gravity="center" 91 android:text="雙句一押" /> 92 93 <RadioButton 94 android:id="@+id/rb_2y" 95 android:layout_width="0dp" 96 android:layout_height="wrap_content" 97 android:layout_weight="1" 98 android:gravity="center" 99 android:text="雙句押韻" /> 100 101 <RadioButton 102 android:id="@+id/rb_3y" 103 android:layout_width="0dp" 104 android:layout_height="wrap_content" 105 android:layout_weight="1" 106 android:gravity="center" 107 android:text="一三四押" /> 108 </RadioGroup> 109 <EditText 110 android:id="@+id/et_key" 111 android:layout_width="match_parent" 112 android:layout_height="wrap_content" 113 android:hint="請輸入藏頭詩"/> 114 <Button 115 android:id="@+id/btn_submit" 116 android:layout_width="match_parent" 117 android:layout_height="wrap_content" 118 android:text="提交"/> 119 120 <ScrollView 121 android:layout_width="match_parent" 122 android:layout_height="match_parent"> 123 <TextView 124 android:id="@+id/tv_show" 125 android:layout_width="match_parent" 126 android:layout_height="match_parent" /> 127 </ScrollView> 128 129 130 131 </LinearLayout>
java代碼目錄結構:
首先需要一個bean,藏頭詩對象原型

1 public class CangTouShiBean { 2 3 4 /** 5 * showapi_res_code : 0 6 * showapi_res_error : 7 * showapi_res_body : {"ret_code":0,"list":["北風勇士馬,晚水獨芙蓉。吾將寶非寶,英雄徒自強。","朝騎五花馬,太華三芙蓉。吾將寶非寶,天子貴文強。","請歌牽白馬,菡萏金芙蓉。大位天下寶,自從冒頓強。","青絲系五馬,秀出九芙蓉。邁德惟家寶,日來知自強。","北買黨項馬,美女誇芙蓉。河宗來獻寶,十年思自強。","青絲系五馬,大嫂采芙蓉。葯妙靈仙寶,不獨有文強。"]} 8 */ 9 10 private int showapi_res_code; 11 private String showapi_res_error; 12 private ShowapiResBodyBean showapi_res_body; 13 14 15 @Override 16 public String toString() { 17 return "CangTouShiBean{" + 18 "showapi_res_code=" + showapi_res_code + 19 ", showapi_res_error='" + showapi_res_error + '\'' + 20 ", showapi_res_body=" + showapi_res_body + 21 '}'; 22 } 23 24 public int getShowapi_res_code() { 25 return showapi_res_code; 26 } 27 28 public void setShowapi_res_code(int showapi_res_code) { 29 this.showapi_res_code = showapi_res_code; 30 } 31 32 public String getShowapi_res_error() { 33 return showapi_res_error; 34 } 35 36 public void setShowapi_res_error(String showapi_res_error) { 37 this.showapi_res_error = showapi_res_error; 38 } 39 40 public ShowapiResBodyBean getShowapi_res_body() { 41 return showapi_res_body; 42 } 43 44 public void setShowapi_res_body(ShowapiResBodyBean showapi_res_body) { 45 this.showapi_res_body = showapi_res_body; 46 } 47 48 public static class ShowapiResBodyBean { 49 /** 50 * ret_code : 0 51 * list : ["北風勇士馬,晚水獨芙蓉。吾將寶非寶,英雄徒自強。","朝騎五花馬,太華三芙蓉。吾將寶非寶,天子貴文強。","請歌牽白馬,菡萏金芙蓉。大位天下寶,自從冒頓強。","青絲系五馬,秀出九芙蓉。邁德惟家寶,日來知自強。","北買黨項馬,美女誇芙蓉。河宗來獻寶,十年思自強。","青絲系五馬,大嫂采芙蓉。葯妙靈仙寶,不獨有文強。"] 52 */ 53 54 private int ret_code; 55 private List<String> list; 56 57 58 @Override 59 public String toString() { 60 return "ShowapiResBodyBean{" + 61 "ret_code=" + ret_code + 62 ", list=" + list + 63 '}'; 64 } 65 66 public int getRet_code() { 67 return ret_code; 68 } 69 70 public void setRet_code(int ret_code) { 71 this.ret_code = ret_code; 72 } 73 74 public List<String> getList() { 75 return list; 76 } 77 78 public void setList(List<String> list) { 79 this.list = list; 80 } 81 } 82 }
其次實藏頭詩的接口,根據藏頭詩的類型參數,請求數據,使用回調接口返回數據

1 public interface BeanCallback<T> { 2 3 void onError(String msg); 4 void onSuccess(T t); 5 }

1 public interface ICangTouShi { 2 //請求數據,需要有變化的參數 3 void doRequest(String num, String type, String yayuntype, String key,BeanCallback<CangTouShiBean> callback); 4 5 }
藏頭詩的model實現藏頭詩的接口,並實現請求數據的方法

1 public class CangTouShiModel implements ICangTouShi{ 2 @Override 3 public void doRequest(String num, String type, String yayuntype, String key, final BeanCallback<CangTouShiBean> callback) { 4 5 //請求數據 6 //使用OkHttp 7 8 OkHttpClient client = new OkHttpClient(); 9 10 RequestBody body = new FormBody.Builder() 11 .add("showapi_appid","27306") 12 .add("showapi_sign","150e9206e7f542bab4affe49d73cb920") 13 .add("num",num) 14 .add("type",type) 15 .add("yayuntype",yayuntype) 16 .add("key",key).build(); 17 18 Request request = new Request.Builder() 19 .post(body) 20 .url("http://route.showapi.com/950-1").build(); 21 Call call = client.newCall(request); 22 //異步請求,子線程 23 call.enqueue(new Callback() { 24 @Override 25 public void onFailure(Call call, IOException e) { 26 Log.e("TAG","-----------"+e.getMessage()); 27 callback.onError(e.getMessage()); 28 } 29 30 @Override 31 public void onResponse(Call call, Response response) throws IOException { 32 String json = response.body().string(); 33 Gson gson = new Gson(); 34 CangTouShiBean bean = gson.fromJson(json, CangTouShiBean.class); 35 callback.onSuccess(bean); 36 } 37 }); 38 39 } 40 41 }
View層即Activity中,加載視圖

1 public class MainActivity extends AppCompatActivity { 2 3 //邏輯判斷,UI操作 4 5 RadioGroup rg_57,rg_ct,rg_yy; 6 EditText et_key; 7 Button btn_submit; 8 TextView tv_show; 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_main); 14 initView(); 15 registerListener(); 16 } 17 18 private void registerListener() { 19 //邏輯控制 20 //實際上就只要監聽提交按鈕即可,因為其他的按鈕只是獲取數據,不需要按下后立即更改UI 21 22 btn_submit.setOnClickListener(new View.OnClickListener() { 23 @Override 24 public void onClick(View view) { 25 String key = et_key.getText().toString(); 26 if(TextUtils.isEmpty(key)){ 27 Toast.makeText(MainActivity.this,"key不能為空",Toast.LENGTH_SHORT).show(); 28 return; 29 } 30 String num = rg_57.getCheckedRadioButtonId()==R.id.rb_5?"5":"7"; 31 String type = null; 32 switch (rg_ct.getCheckedRadioButtonId()){ 33 case R.id.rb_ct: 34 type = "1"; 35 break; 36 case R.id.rb_cw: 37 type = "2"; 38 break; 39 case R.id.rb_cz: 40 type = "3"; 41 break; 42 case R.id.rb_dz: 43 type = "4"; 44 break; 45 case R.id.rb_dj: 46 type = "5"; 47 break; 48 } 49 String yy = null; 50 switch (rg_yy.getCheckedRadioButtonId()){ 51 case R.id.rb_1y: 52 yy="1"; 53 break; 54 case R.id.rb_2y: 55 yy="2"; 56 break; 57 case R.id.rb_3y: 58 yy="3"; 59 break; 60 } 61 62 final ProgressDialog dialog = new ProgressDialog(MainActivity.this); 63 dialog.setTitle("提示"); 64 dialog.setMessage("開始請求"); 65 dialog.show(); 66 67 //請求數據 68 CangTouShiModel model = new CangTouShiModel(); 69 //OkHttp的異步請求,在子線程中 70 model.doRequest(num, type, yy, key, new BeanCallback<CangTouShiBean>() { 71 @Override 72 public void onError(String msg) { 73 runOnUiThread(new Runnable() { 74 @Override 75 public void run() { 76 dialog.dismiss(); 77 Toast.makeText(MainActivity.this,"msg",Toast.LENGTH_SHORT).show(); 78 79 } 80 }); 81 } 82 83 @Override 84 public void onSuccess(final CangTouShiBean bean) { 85 runOnUiThread(new Runnable() { 86 @Override 87 public void run() { 88 dialog.dismiss(); 89 List<String> list = bean.getShowapi_res_body().getList(); 90 tv_show.setText(""); 91 for (String s : list) { 92 tv_show.append(s+"\n"); 93 } 94 95 } 96 }); 97 98 } 99 }); 100 } 101 }); 102 103 } 104 105 private void initView() { 106 rg_57 = (RadioGroup) findViewById(R.id.rg_57); 107 rg_57.check(R.id.rb_5); 108 rg_ct = (RadioGroup) findViewById(R.id.rg_ct); 109 rg_ct.check(R.id.rb_ct); 110 rg_yy = (RadioGroup) findViewById(R.id.rg_yy); 111 rg_yy.check(R.id.rb_1y); 112 et_key = (EditText) findViewById(R.id.et_key); 113 btn_submit = (Button) findViewById(R.id.btn_submit); 114 tv_show = (TextView) findViewById(R.id.tv_show); 115 116 117 } 118 119 120 }
在MVC模式中我們發現,其實控制器Activity主要是起到解耦作用,將View視圖和Model模型分離,雖然Activity起到交互作用,但是找Activity中有很多關於視圖UI的顯示代碼,因此View視圖和Activity控制器並不是完全分離的,也就是說一部分View視圖和Contronller控制器Activity是綁定在一個類中的。
MVC的優點:
(1)耦合性低。所謂耦合性就是模塊代碼之間的關聯程度。利用MVC框架使得View(視圖)層和Model(模型)層可以很好的分離,這樣就達到了解耦的目的,所以耦合性低,減少模塊代碼之間的相互影響。
(2)可擴展性好。由於耦合性低,添加需求,擴展代碼就可以減少修改之前的代碼,降低bug的出現率。
(3)模塊職責划分明確。主要划分層M,V,C三個模塊,利於代碼的維護。