主要分析这几个架构的特性,优缺点,以及App架构设计中应该注意的问题
1、MVC设计架构(Model-View-Controller)
(1)简介:MVC全名是Model View Controller,是模型,视图,控制器的缩写,用一种业务逻辑,数据,界面显示分离的方法组织代码,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑(M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁作用,来控制V层和M层通信以此来达到分离视图显示和业务逻辑层)
(2)Android中的MVC
视图层(View)
一般采用XML文件进行界面的描述,这些XML可以理解为View,使用的时候可以非常方便的引入。同时便于后期界面的修改。逻辑中界面对应的id不变则代码不用修改,大大增加了代码的可维护性。
模型层(Model)
针对业务模型,建立的数据结构和相关的类,就可以理解为Model,Model是与View无关,而与业务相关的。
控制层(Controller)
控制层通常是Activity,不要再Activity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另一个原因是Android中的Activity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。
(3)总结:(用户)→ (View)→ (Activity)→ (Model)→ (Activity)→ (View)→ (用户)
(4)MVC的缺点: 在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。
2、MVP设计架构(Model-View-Presenter)
(1)简介:MVP从更早的MVC框架演变过来,与MVC有一定的相似性:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
View→ Presenter→ Model→ Presenter→ View
MVP框架由3部分组成:View负责显示,Presenter负责逻辑处理,Model提供数据。在MVP模式里通常包含3个要素(加上View interface是4个)
View:负责绘制UI元素,与用户进行交互(在Android中体现为Activity)
Model:负责存储,检索,操纵数据(有时也实现一个Model interface用来降低耦合)
Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑
View interface:需要VIiew实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试
(2)View interface的必要性
在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,这说明我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试时间。
(3) 具体到AndroidApp中,一般可以将App根据程序的结构进行纵向划分,根据MVP可以将App分别为模型层(M),UI层(V)和逻辑层(P)。
UI层一般包括Activity,Fragment,Adapter等直接和UI相关的类,UI层的Activity在启动之后实例化相应的Presenter,App的控制权后移,由UI转移到Presenter,两者之间的通信通过BroadCast、Handler或者接口完成,只传递事件和结果。
举例: UI层通知逻辑层(Presenter)用户点击了一个Button,逻辑层(Presenter)自己决定应该用什么行为进行响应,该找哪个模型(Model)去做这件事,最后逻辑层(Presenter)将完成的结果更新到UI层。
(4)MVP的优点
在MVP中,Activity的代码不臃肿;
在MVP中,Model(IUserModel的实现类)的改动不会影响Activity(View),两者也互不干涉,而在MVC中会;
在MVP中,IUserView这个接口可以实现方便地对Presenter的测试;
在MVP中,UserPresenter可以用于多个视图,但是在MVC中的Activity就不行。
代码如下:
(一)View(Presenter与View交互是通过接口实现的,所以我们需要定义一个接口IUserView(难点在于IUserView中应该有哪些方法))
public interface IUserView {
String getUserName();
String getPassWord();
void toMainActivity(User user);
void showFailedError();
}
public class UserActivity extends Activity implements View.OnClickListener, IUserView{
private TextView tv_password;
private TextView tv_username;
private Button btn_login;
private UserPresenter userPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mvp_user);
tv_password = (TextView) findViewById(R.id.tv_password);
tv_username = (TextView) findViewById(R.id.tv_username);
btn_login = (Button) findViewById(R.id.btn_login);
btn_login.setOnClickListener(this);
userPresenter = new UserPresenter(this);
}
@Override
public void onClick(View v) {
userPresenter.login();
}
@Override
public String getUserName() {
return tv_username.getText().toString();
}
@Override
public String getPassWord() {
return tv_password.getText().toString();
}
@Override
public void toMainActivity(User user) {
Log.i("loginSuccess", "username" + user.getUsername() + ": password" + user.getPassword());
}
@Override
public void showFailedError() {
Log.i("loginSuccess", "登录失败");
}
}
(二)Model(抽取一个业务类接口IUserModel和一个返回是否成功接口OnLoginListener)
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
public interface IUserModel {
void login(String username, String password, OnLoginListener onLoginListener);
}
public interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}
public class UserModel implements IUserModel{
@Override
public void login(String username, String password, OnLoginListener onLoginListener) {
if ("zhy".equals(username) && "123".equals(password))
{
User user = new User();
user.setUsername(username);
user.setPassword(password);
onLoginListener.loginSuccess(user);
} else
{
onLoginListener.loginFailed();
}
}
}
(三)Presenter(我们的presenter完成二者的交互,那么肯定需要二者的实现类。大致就是从View中获取需要的参数,交给Model去执行业务方法,执行的过程中需要的反馈,以及结果,再让View进行做对应的显示。)
public class UserPresenter{
private UserModel userModel;
private IUserView iUserView;
public UserPresenter(IUserView iUserView){
this.iUserView = iUserView;
}
public void login(){
userModel = new UserModel();
userModel.login(iUserView.getUserName(), iUserView.getPassWord(), new OnLoginListener() {
@Override
public void loginSuccess(User user) {
iUserView.toMainActivity(user);
}
@Override
public void loginFailed() {
iUserView.showFailedError();
}
});
}
}
3、MVVM设计模式(Model,View,ViewModel)
在MVP中,我们需要Model,View,Presenter三样进行配合使用,但是在View中还是会出现大量的类似ShowLoad之类的代码,而这在MVVM是由Model,View,ViewModel进行配合的。其中主要区别在于ViewModel,Data Binding 的奇妙之处在于可以将 XML 文件与指定的 JAVA 类绑定 , 实现数据自动更新的效果 .
使用步骤
1.在build.gradle文件中添加如下部分
dataBinding{
enabled = true
}
2.在XML文件中
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.shire.mvvmdemo.viewModel.User"/>
</data>
<RelativeLayout
android:id="@+id/rl_time"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text="@{user.username}"
android:textColor="#555555"
android:textSize="18dp" />
<TextView
android:id="@+id/tv_workShift"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:layout_marginTop="10dp"
android:text="@{user.password}"
android:textColor="#999999"
android:textSize="9dp" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/sizeLine"
android:layout_below="@id/tv_time"
android:background="@color/colorLine" />
</RelativeLayout>
</layout>
根节点是layout
3.在activity文件中
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(new User("123","123"));
}
}