FROM:
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三个模块,利于代码的维护。