Android进阶笔记07:Android之MVC 理解
1. 为什么需要MVC ?
软件中最核心的,最基本的东西是什么?
答:是的,是数据。我们写的所有代码,都是围绕数据的。
围绕着数据的产生、修改等变化,出现了业务逻辑。
围绕着数据的显示,出现了不同的界面技术。没有很好设计的代码,常常就会出现数据层(持久层)和业务逻辑层还有界面代码耦合的情况。ORM等框架,解耦合了业务逻辑和数据之间的耦合,业务逻辑不再关心底层数据如何存储和读取。所有数据呈现给业务逻辑层的就是一个个的对象。而MVC, MVP, MMVM用来解决业务逻辑和视图之间的耦合。
2. MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。其中M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信以此来达到分离视图显示View和业务逻辑层Model。MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
说了这么多,听着感觉很抽象,废话不多说,我们来看看MVC在Android开发中是怎么应用的吧!
Model层是一个应用系统的核心部分,代表了该系统实际要实现的所有功能处理。比如:在视频播放器中,模型代表一个视频数据库及播放视频的程序函数代码;在拍照应用中,模型代表一个照片数据库,及看图片时的程序函数代码。在一个电话应用中,Model代表一个电话号码簿,以及拨打电话和发送短信的程序函数代码。
Model在values目录下通过xml文件格式生成,也可以通过硬编码的方式直接Java代码生成。View和Model是通过桥梁Adapter来连接起来。
总而言之,MVC框架如下:
- View 是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
- Controller 是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,想用用户出发的相关事件,交给Model处理。
- Model 应用程序的主体部分,所有的业务逻辑都应该写在该层。
1 public class ArrayAdapterActivity extends Activity { 2 @Override 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 6 ListView listView = new ListView(this); 7 8 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData()); 9 10 listView.setAdapter(adapter); 11 setContentView(listView); 12 // 点击事件,Controller负责 13 listView.setOnItemClickListener(new OnItemClickListener() { 14 @Override 15 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 16 // position是从0开始的,获取点击item的内容 17 Toast.makeText(ArrayAdapterActivity.this, getData().get(position), Toast.LENGTH_SHORT).show(); 18 } 19 }); 20 } 21 // 要显示的数据Model,通过硬编码的方式直接Java代码生成 22 private List<String> getData() { 23 List<String> data = new ArrayList<String>(); 24 data.add("a"); 25 data.add("b"); 26 data.add("c"); 27 data.add("d"); 28 return data; 29 } 30 }
• 视图View和模型Model取资源文件方式:
先在res/layout文件夹下创建文件activity_arrayadapter.xml,可以看出只包含一个ListView,即视图View
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 <ListView 7 android:id="@+id/listview" 8 android:layout_width="fill_parent" 9 android:layout_height="fill_parent" 10 android:drawSelectorOnTop="false" /> 11 </LinearLayout>
在res/values文件夹下的strings.xml添加一个字符数组,及模型Model
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <string-array name="good"> 4 <item>a</item> 5 <item>b</item> 6 <item>c</item> 7 <item>d</item> 8 </string-array> 9 </resources>
Activity代码,在注释中讲解MVC模型使用:
1 public class ArrayAdapterActivity2 extends Activity { 2 @Override 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 setContentView(R.layout.activity_arrayadapter); 6 7 ListView listView = (ListView) findViewById(R.id.listview); 8 9 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData()); 10 11 listView.setAdapter(adapter); 12 // 点击事件,Controller负责 13 listView.setOnItemClickListener(new OnItemClickListener() { 14 @Override 15 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 16 // position是从0开始的,获取点击item的内容 17 Toast.makeText(ArrayAdapterActivity2.this, getData().get(position), Toast.LENGTH_SHORT).show(); 18 } 19 }); 20 } 21 // 要显示的数据Model,Model在values目录下通过xml文件格式生成 22 private List<String> getData() { 23 List<String> data = new ArrayList<String>(); 24 Resources res =getResources(); 25 // 取xml文件格式的字符数组 26 String[] good=res.getStringArray(R.array.good); 27 for(int i=0;i<good.length;i++){ 28 data.add(good[i]); 29 } 30 return data; 31 } 32 }
Android的MVC模式要在项目中慢慢理解,这样才能理解透彻并活学活用。
- Controller控制器:
1 package com.xjp.androidmvcdemo.controller; 2 3 import android.app.Dialog; 4 import android.app.ProgressDialog; 5 import android.os.Bundle; 6 import android.support.v7.app.ActionBarActivity; 7 import android.view.View; 8 import android.widget.EditText; 9 import android.widget.TextView; 10 import android.widget.Toast; 11 12 import com.xjp.androidmvcdemo.R; 13 import com.xjp.androidmvcdemo.entity.Weather; 14 import com.xjp.androidmvcdemo.entity.WeatherInfo; 15 import com.xjp.androidmvcdemo.model.OnWeatherListener; 16 import com.xjp.androidmvcdemo.model.WeatherModel; 17 import com.xjp.androidmvcdemo.model.WeatherModelImpl; 18 19 20 public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener { 21 22 private WeatherModel weatherModel; 23 private Dialog loadingDialog; 24 private EditText cityNOInput; 25 private TextView city; 26 private TextView cityNO; 27 private TextView temp; 28 private TextView wd; 29 private TextView ws; 30 private TextView sd; 31 private TextView wse; 32 private TextView time; 33 private TextView njd; 34 35 @Override 36 protected void onCreate(Bundle savedInstanceState) { 37 super.onCreate(savedInstanceState); 38 setContentView(R.layout.activity_main); 39 weatherModel = new WeatherModelImpl(); 40 initView(); 41 } 42 43 /** 44 * 初始化View 45 */ 46 private void initView() { 47 cityNOInput = findView(R.id.et_city_no); 48 city = findView(R.id.tv_city); 49 cityNO = findView(R.id.tv_city_no); 50 temp = findView(R.id.tv_temp); 51 wd = findView(R.id.tv_WD); 52 ws = findView(R.id.tv_WS); 53 sd = findView(R.id.tv_SD); 54 wse = findView(R.id.tv_WSE); 55 time = findView(R.id.tv_time); 56 njd = findView(R.id.tv_njd); 57 findView(R.id.btn_go).setOnClickListener(this); 58 59 loadingDialog = new ProgressDialog(this); 60 loadingDialog.setTitle(加载天气中...); 61 62 63 } 64 65 /** 66 * 显示结果 67 * 68 * @param weather 69 */ 70 public void displayResult(Weather weather) { 71 WeatherInfo weatherInfo = weather.getWeatherinfo(); 72 city.setText(weatherInfo.getCity()); 73 cityNO.setText(weatherInfo.getCityid()); 74 temp.setText(weatherInfo.getTemp()); 75 wd.setText(weatherInfo.getWD()); 76 ws.setText(weatherInfo.getWS()); 77 sd.setText(weatherInfo.getSD()); 78 wse.setText(weatherInfo.getWSE()); 79 time.setText(weatherInfo.getTime()); 80 njd.setText(weatherInfo.getNjd()); 81 } 82 83 /** 84 * 隐藏进度对话框 85 */ 86 public void hideLoadingDialog() { 87 loadingDialog.dismiss(); 88 } 89 90 91 @Override 92 public void onClick(View v) { 93 switch (v.getId()) { 94 case R.id.btn_go: 95 loadingDialog.show(); 96 weatherModel.getWeather(cityNOInput.getText().toString().trim(), this); 97 break; 98 } 99 } 100 101 @Override 102 public void onSuccess(Weather weather) { 103 hideLoadingDialog(); 104 displayResult(weather); 105 } 106 107 @Override 108 public void onError() { 109 hideLoadingDialog(); 110 Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show(); 111 } 112 113 private <t extends="" view=""> T findView(int id) { 114 return (T) findViewById(id); 115 } 116 117 }
- Model模型
来看看WeatherModelImpl代码实现:
1 package com.xjp.androidmvcdemo.model; 2 3 /** 4 * Description:请求网络数据接口 5 * User: xjp 6 * Date: 2015/6/3 7 * Time: 15:40 8 */ 9 10 public interface WeatherModel { 11 void getWeather(String cityNumber, OnWeatherListener listener); 12 } 13 14 ................ 15 16 17 package com.xjp.androidmvcdemo.model; 18 19 import com.android.volley.Response; 20 import com.android.volley.VolleyError; 21 import com.xjp.androidmvcdemo.entity.Weather; 22 import com.xjp.androidmvcdemo.volley.VolleyRequest; 23 24 /** 25 * Description:从网络获取天气信息接口实现 26 * User: xjp 27 * Date: 2015/6/3 28 * Time: 15:40 29 */ 30 31 public class WeatherModelImpl implements WeatherModel { 32 33 @Override 34 public void getWeather(String cityNumber, final OnWeatherListener listener) { 35 36 /*数据层操作*/ 37 VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html, 38 Weather.class, new Response.Listener<weather>() { 39 @Override 40 public void onResponse(Weather weather) { 41 if (weather != null) { 42 listener.onSuccess(weather); 43 } else { 44 listener.onError(); 45 } 46 } 47 }, new Response.ErrorListener() { 48 @Override 49 public void onErrorResponse(VolleyError error) { 50 listener.onError(); 51 } 52 }); 53 } 54 }
以上代码看出,这里设计了一个WeatherModel模型接口,然后实现了接口WeatherModelImpl类。controller控制器activity调用WeatherModelImpl类中的方法发起网络请求,然后通过实现OnWeatherListener接口来获得网络请求的结果通知View视图层更新UI 。至此,Activity就将View视图显示和Model模型数据处理隔离开了。activity担当contronller完成了model和view之间的协调作用。
至于这里为什么不直接设计成类里面的一个getWeather()方法直接请求网络数据?你考虑下这种情况:现在代码中的网络请求是使用Volley框架来实现的,如果哪天老板非要你使用Afinal框架实现网络请求,你怎么解决问题?难道是修改 getWeather()方法的实现? no no no,这样修改不仅破坏了以前的代码,而且还不利于维护, 考虑到以后代码的扩展和维护性,我们选择设计接口的方式来解决着一个问题,我们实现另外一个WeatherModelWithAfinalImpl类,继承自WeatherModel,重写里面的方法,这样不仅保留了以前的WeatherModelImpl类请求网络方式,还增加了WeatherModelWithAfinalImpl类的请求方式。Activity调用代码无需要任何修改。
MVC使用总结
利用MVC设计模式,使得这个天气预报小项目有了很好的可扩展和维护性,当需要改变UI显示的时候,无需修改Contronller(控制器)Activity的代码和Model(模型)WeatherModel模型中的业务逻辑代码,很好的将业务逻辑和界面显示分离。
在Android项目中,业务逻辑,数据处理等担任了Model(模型)角色,XML界面显示等担任了View(视图)角色,Activity担任了Contronller(控制器)角色。contronller(控制器)是一个中间桥梁的作用,通过接口通信来协同 View(视图)和 Model(模型)工作,起到了两者之间的通信作用。
什么时候适合使用MVC设计模式?当然一个小的项目且无需频繁修改需求就不用MVC框架来设计了,那样反而觉得代码过度设计,代码臃肿。一般在大的项目中,且业务逻辑处理复杂,页面显示比较多,需要模块化设计的项目使用MVC就有足够的优势了。
在MVC模式中我们发现,其实控制器Activity主要是起到解耦作用,将View视图和Model模型分离,虽然Activity起到交互作用,但是找Activity中有很多关于视图UI的显示代码,因此View视图和Activity控制器并不是完全分离的,也就是说一部分View视图和Contronller控制器Activity是绑定在一个类中的。
MVC的优点:
- 耦合性低。所谓耦合性就是模块代码之间的关联程度。利用MVC框架使得View(视图)层和Model(模型)层可以很好的分离,这样就达到了解耦的目的,所以耦合性低,减少模块代码之间的相互影响。
- 可扩展性好。由于耦合性低,添加需求,扩展代码就可以减少修改之前的代码,降低bug的出现率。
- 模块职责划分明确。主要划分层M,V,C三个模块,利于代码的维护。
转载于:https://www.cnblogs.com/hebao0514/p/4953993.html
Android进阶笔记07:Android之MVC 理解相关推荐
- Android进阶笔记:Messenger源码详解
Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...
- Android 进阶笔记,包含常用的技术框架、博客社区、书籍等。
AndroidNote 项目地址:venshine/AndroidNote 简介:Android 进阶笔记,包含常用的技术框架.博客社区.书籍等. 大纲 技术框架 图片加载 网络请求 数据库 ORM ...
- Android 进阶笔记。
本文转载自:Wei_Leng http://blog.csdn.net/u014608640/article/details/53063761 AndroidNote 项目地址:venshi ...
- Android进阶笔记:AIDL内部实现详解 (二)
接着上一篇分析的aidl的流程解析.知道了aidl主要就是利用Ibinder来实现跨进程通信的.既然是通过对Binder各种方法的封装,那也可以不使用aidl自己通过Binder来实现跨进程通讯.那么 ...
- Android学习笔记:Android基础知识点(不断更新中)
1.Android学习笔记:OkHttp 2.Android学习笔记:更新UI的方法(UI线程和非UI线程) 3.Android学习笔记:Volley 4.Android学习笔记:Handler 5. ...
- 我的Android进阶之旅------Android利用Sensor(传感器)实现水平仪功能的小例
这里介绍的水平仪,指的是比较传统的气泡水平仪,在一个透明圆盘内充满液体,液体中留有一个气泡,当一端翘起时,该气泡就会浮向翘起的一端. 利用方向传感器返回的第一个参数,实现了一个指南针小应用. ...
- 我的Android进阶之旅------Android利用温度传感器实现带动画效果的电子温度计
要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...
- android服务进阶,我的Android进阶之旅------Android服务的生命周期回调方法
先引用一段官网上的文字 ======================================================================================== ...
- 我的Android进阶之旅------Android项目目录结构分析
此文章来自"博客园"博主,仅在此借鉴,学习 1.HelloWorld项目的目录结构 1.1.src文件夹 1.2.gen文件夹 1.3.Android 2.1文件夹 1.4.ass ...
最新文章
- 刷牙刷了这么多年,我们居然都搞错了!
- python猜数字游戏简单-python猜数字游戏快速求解解决方案
- 多维数据查询效率分析(1)
- 中国钢铁行业产量规模与十四五建设动态分析报告2022-2027年
- CentOS7 firewalld防火墙配置
- 数学建模:1.概述 监督学习--回归分析模型
- 来看看这些门户网站的变迁史 - 感受下网络发展的这段过往
- linux线程相关函数接口
- HDU1175 连连看【DFS】
- 线上python课程一般多少钱-排名前十的python零基础编程在线网课一对一费用多少钱...
- 抖音上热门精选技巧 小视频更改md5
- [论文阅读笔记47]ZEN-BERT-based Chinese (Z) text encoder Enhanced by N-gram representations
- 面板数据随机效应模型下,可行的广义最小二乘法FGLS估计
- 海尔android 电视直播软件,海尔智能电视如何安装直播软件看直播
- 【树 图 科 技 头 条】2022年7月26日 星期二 @伍鸣 博士 受邀参加2022年7月29日举办的“2022开放原子开源峰会-区块链分论坛”并发表主题演讲
- c#后台如何导出excel到本地_C#导出EXCEL方法总结
- xctf攻防世界 MISC高手进阶区 2017_Dating_in_Singapore
- c语言课程设计图书管理系统
- lattepanda安装linux系统,lattepanda alpha Ubuntu18.04下配置串口登录
- 【转】Redis 分布式——可用性保证之 Sentinel(实战篇)
热门文章
- python 苹果李子橙_Python模块知识6:OS、SYS模块
- head在c语言中的作用,阅读以下说明和C语言函数,将应填入(n)处的字句写在对应栏内。【说明】 函数sort (NODE *head)的功能 - 赏学吧...
- jdk javac运行不了_Intellij IDEA搭建jdk源码阅读环境
- nginx启动只有master没有worker_深入浅出Nginx
- js map遍历 修改对象里面的值_求职季之你必须要懂的原生JS(上)
- mysql与ms sql server_MS SQL Server和MySQL区别
- css3选项卡样式,css3选项卡标题样式设计1
- 过渡元素最外层电子数_元素周期表
- python命名空间更改_在Python中使用ElementTree改变命名空间前缀
- 小米Max怎么刷入开发版获得root超级权限