Android项目中,主要用到Activity与layout布局,大体上即呈现MVC的结构,在Android开发中,常用到的开发模式有MVC、MVP、MVVM,在此作简要介绍。

一、MVC

Android项目入手,初学者都知道创建一个Activity,随后即产生一个界面,开启HelloWorld之旅。

由于此种模式的存在,项目自然而然呈现MVC模式,Model-View-Controller,layout作为布局文件,充当着视图View的角色,而Activity作为一个庞大的Controller,控制M和V,View接受交互请求,并把请求交给Controller,Controller操作Model进行数据更新,数据更新之后,Model通知View数据变化,从而使View显示更新之后的数据。

一个简单的例子:登录功能。

创建一个LoginActivity,界面中有两个输入框EditText与一个按钮Button,输入用户名密码来登录。登录功能代码如下:

public void login(View view){
       String userName=et_username.getText().toString();
       String passWord=et_password.getText().toString();
       final User user=new User(userName,passWord);
       doLogin(user);
    }
   
   private void doLogin(final User user){
       new Thread(){
           @Override
           public void run() {
                super.run();
                //网络执行登录操作
                booleanlogin=checkUserInfo(user);
                if (login) {
                    runOnUiThread(newRunnable() {
                       @Override
                        public void run() {
                           Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_SHORT).show();
                        }
                    });
                }else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                           Toast.makeText(LoginActivity.this,"登录失败",Toast.LENGTH_SHORT).show();
                        }
                    });
                }
           }
       }.start();
    }



除去User类封装了userName和passWord,其余所有代码都放在Activity中,这是一个简单的MVC模式,但是,显得很是臃肿,可以通过方法的抽取,把login()方法中的逻辑代码简化一下,但抽取出来的代码仍放在Activity中,如果一个界面中有很多逻辑功能,相对应的方法数就会有很多个,维护起来也略显繁杂。

         Activity在上述功能中,由逻辑功能代码和界面显示代码组成,如果能将一部分抽取出去另外处理,可以对Activity进行瘦身。对C进行延伸,把业务逻辑抽取,产生了MVP(Model-View-Presenter)模式,对界面显示抽取,产生了MVVM(Model-View-ViewModel)模式。

二、MVP

View接受用户的交互请求,将请求转交给Presenter,Presenter操作Model进行数据更新,数据更新之后,Model通知Presenter数据发生变化,Presenter更新View的数据

 

首先写一个类LoginPresenter,把业务逻辑代码抽取到其中处理,并把与界面显示的代码还留在Activity中。那么,登录成功与否的逻辑需要在Activity中写一个方法来调用,那么,我们在LoginPresenter中需要调用LoginActivity中的代码,传入一个LoginActivity的对象可以解决这个问题,于是,创建一个构造函数LoginPresenter(LoginActivity activity)来传入LoginActivity对象,产生以下代码:

public classLoginPresenter {
    private LoginActivity activity;
    public LoginPresenter(LoginActivityactivity){
        this.activity=activity;
    }
    private void doLogin(final User user){
        new Thread(){
            @Override
            public void run() {
                super.run();
                //网络执行登录操作
                booleanlogin=checkUserInfo(user);
                if (login) {
                    activity.loginSuccess();
                }else {
                    activity.loginFailure();
                }
            }
        }.start();
    }
    private boolean checkUserInfo(User user){
        //网络执行登录操作
        return ...;
    }
}


在LoginActivity中,写出登录成功与失败的界面处理代码如下:

public void loginSuccess() {
       runOnUiThread(new Runnable() {
           @Override
           public void run() {
               Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_SHORT).show();
           }
       });
    }
 
    public void loginFailure() {
       runOnUiThread(new Runnable() {
           @Override
           public void run() {
               Toast.makeText(LoginActivity.this,"登录失败",Toast.LENGTH_SHORT).show();
           }
       });
    }



在LoginActivity中,只用创建一个LoginPresenter类的对象即可调用doLogin方法。

                   这时,思考一个问题,如果要使用的类的是Fragment呢?亦或者是其他任何类呢?显然,这种方式有局限性,好的做法是:不去传入LoginActivity的对象,而是定义一个接口对象传入,通过LoginActivity实现该接口,实现了两者的解耦合。而对于任何需要处理Presenter中功能的类,同样只要实现这个接口即可。定义接口类LoginInterface如下:

public interface LoginInterface {
    void onLoginSuccess();
    void onLoginFailure();
}




将上述LoginPresenter类代码中的LoginActivity改为LoginInterface,并将LoginActivity实现该接口,在两个实现方法中处理对应的结果界面显示。自此,MVP模式的登录功能就实现了。

三、MVVM

而将Activity中与View有关的代码抽取出来,就是MVVM模式。

1.      DataBinding

为了实现V与ViewModle之间的通信,在2015年Google的I/O大会上,推出DataBinding技术支持,目前支持API7及Gradle1.5.0以上。

在使用上很简单,只用在module的gradle文件的android{}中,配置:

dataBinding{
        enabled true
 }

代码实现具体以登录例子为参照,继续将项目改为MVVM。

2.      MVVM的实现

首先将Activity中与View有关的代码删除,即setContentView()方法和findViewById()的代码。onCreat()方法中增加binding代码,如下:

@Override
    protected void onCreate(@Nullable BundlesavedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityLoginBinding binding=DataBindingUtil.setContentView(this,R.layout.activity_login);
}



在layout布局中,将原布局根节点外加一层<layout>节点,并加上<data>节点以绑定。如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
           name="user"
           type="com.cshawn.testmvcpm.User"/>
        <variable
           name="event"
            type="com.cshawn.testmvcpm.UserEvent"/>
    </data>
<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   android:gravity="center">
 
    <EditText
       android:id="@+id/et_username"
        android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="@{user.userName}"
       android:addTextChangedListener="@{event.nameWatcher}"
        android:hint="用户名"/>
    <EditText
       android:id="@+id/et_password"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="@{user.password}"
       android:addTextChangedListener="@{event.passWordWatcher}"
        android:hint="密码"/>
    <Button
       android:id="@+id/btn_login"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:onClick="login"
        android:text="登录"/>
</LinearLayout>
</layout>



布局中的data即是对数据的绑定,将EditText中的数据显示与User中的数据绑定,而EditText数据变化时需要改变User中的值,因而添加TextWatcher。在此创建了一个UserEvent类,创建两个TextWatcher分别监听EditText变化,来改变User的值,实现ViewModle的功能。UserEvent代码如下:

public class UserEvent {
    private User user;
    public UserEvent(Useruser){
        this.user=user;
    }
    public TextWatchernameWatcher=new TextWatcher() {
        @Override
        public voidbeforeTextChanged(CharSequence s, int start, int count, int after) {
 
        }
 
        @Override
        public voidonTextChanged(CharSequence s, int start, int before, int count) {
 
        }
 
        @Override
        public voidafterTextChanged(Editable s) {
           user.setUserName(s.toString());
        }
    };
    public TextWatcherpassWordWatcher=new TextWatcher() {
        @Override
        public voidbeforeTextChanged(CharSequence s, int start, int count, int after) {
 
        }
 
        @Override
        public voidonTextChanged(CharSequence s, int start, int before, int count) {
 
        }
 
        @Override
        public voidafterTextChanged(Editable s) {
           user.setPassword(s.toString());
        }
    };
}

此时,在Activity的onCreate代码中增加数据绑定如下:

user=new User();
UserEvent event=newUserEvent(user);
binding.setEvent(event);

至此,把View部分的代码逻辑全部抽取出去,形成MVVM模式。

四、结语

以上只是对MVC、MVP、MVVM在Android中应用的一个简单介绍,实际项目中,可以对项目结构进行更为简洁的拆分与解耦,具体功能见机行事即可。