Android的MVVM模式优缺点

本文探讨了Android中MVVM设计模式的优缺点。MVVM模式因其代码简洁,类似Vue框架的使用体验而受到青睐。文章通过示例展示了MVVM在实际应用中的五个关键功能,并详细分析了该模式在实际开发中的优势与不足。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MVVM设计模式的优点

1.双向绑定技术,当Model变化时,View-Model会自动更新,View也会自动变化。很好做到数据的一致性,不用担心,在模块的这一块数据是这个值,在另一块就是另一个值了。所以 MVVM模式有些时候又被称作:model-view-binder模式。
2.View的功能进一步的强化,具有控制的部分功能,若想无限增强它的功能,甚至控制器的全部功几乎都可以迁移到各个View上(不过这样不可取,那样View干了不属于它职责范围的事情)。View可以像控制器一样具有自己的View-Model.
3.由于控制器的功能大都移动到View上处理,大大的对控制器进行了瘦身。不用再为看到庞大的控制器逻辑而发愁了。
4.可以对View或ViewController的数据处理部分抽象出来一个函数处理model。这样它们专职页面布局和页面跳转,它们必然更一步的简化。


MVVM设计模式的缺点

第一点:数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。
第二点:一个大的模块中,model也会很大,虽然使用方便了也很容易保证了数据的一致性,当时长期持有,不释放内存,就造成了花费更多的内存。
第三点:数据双向绑定不利于代码重用。客户端开发最常用的重用是View,但是数据双向绑定技术,让你在一个View都绑定了一个model,不同模块的model都不同。那就不能简单重用View了。


个人还是比较喜欢MVVM模式的,使用起来,代码简洁了很多,有点像H5的Vue框架。

下面是示例,示例演示了下面5个MVVM功能:

1.基本使用

 2.绑定ImageView

 3.绑定ListView

 4.点击事件处理

 5.数据更新处理


package shenbin.com.demo17101101.mvvp;

import android.app.Activity;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

import shenbin.com.demo17101101.BR;
import shenbin.com.demo17101101.R;
import shenbin.com.demo17101101.databinding.ActivityMvvmDemoBinding;

/**
 * 这个demo包含mvvm模式的:
 *
 * 1.基本使用

 2.绑定ImageView

 3.绑定ListView

 4.点击事件处理

 5.数据更新处理
 */
public class MvvmDemoActivity extends Activity {

    ActivityMvvmDemoBinding binding = null;

    private ListView lv = null;
    private LvAdapter<User> adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_mvvm_demo);

        //ActivityMvvmDemoBinding 这个是根据布局文件名R.layout.activity_mvvm_demo 得到的。
        binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm_demo);
        User user = new User("shenbin", "走在勇往直前的路上");
        binding.setUser(user);

        initView();

        getDatas();

    }

    private void getDatas() {
        List<User> datas = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User("shenbin"+i,"沈斌是个好男人"+i*i);
            datas.add(user);
        }

        adapter.setDatas(datas);

    }

    private void initView() {
        lv = (ListView) findViewById(R.id.lv);
        adapter = new LvAdapter<User>(this,R.layout.item_lv_mvvm, BR.user);
        lv.setAdapter(adapter);
    }

}
 
 
package shenbin.com.demo17101101.mvvp;

import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.BindingAdapter;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import shenbin.com.demo17101101.BR;
import shenbin.com.demo17101101.R;

/**
 * Created by Administrator--沈斌 on 2017/10/11.
 * 一:
 * 如果需要数据更新,就需要
 * 1,extends BaseObservable
 * 2,在对应的属性set方法里面
 * 包名+".BR."+属性名
    notifyPropertyChanged(shenbin.com.demo17101101.BR.name);
 * 3,在对应的属性的get方法前面添加:@Bindable
 * 这样就可以实时更新UI了
 *
 * 二:imageView
 *
 *
 */
public class User extends BaseObservable {

    public User(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    private String name;
    private String desc;
    private String imgUrl;

    public String getImgUrl() {
        return imgUrl;
    }

    public void setImgUrl(String imgUrl) {
        this.imgUrl = imgUrl;
    }

    public void onItemClick(View v){
        setName("change");
        setDesc("hahhhhhhh");
        Log.e("tag",getName());
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        //包名+".BR."+属性名
        notifyPropertyChanged(shenbin.com.demo17101101.BR.name);
    }

    @Bindable
    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
        notifyPropertyChanged(BR.desc);
    }

    /**
     * 这个方法会自动调用 只要设置了img这个自定义属性。
     * @param iv
     * @param imgUrl
     */
    @BindingAdapter("bind:img")
    public static void setImageView(ImageView iv,String imgUrl){
        iv.setImageResource(R.drawable.ic_launcher);
        //可以使用网络地址,用图片框架请求image-loader,picaso
    }
}

package shenbin.com.demo17101101.mvvp;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator--沈斌 on 2017/10/11.
 */
public class LvAdapter<T> extends BaseAdapter {

    private List<T> datas = new ArrayList<>();
    private Context context;
    private LayoutInflater inflater;
    private int layoutId;
    private int variableId;

    public LvAdapter(Context context, int layoutId, int variableId,List<T> datas) {
        this.context = context;
        this.layoutId = layoutId;
        this.variableId = variableId;
        inflater = LayoutInflater.from(context);
        this.setDatas(datas);
    }

    public LvAdapter(Context context, int layoutId, int variableId) {
        this.context = context;
        this.layoutId = layoutId;
        this.variableId = variableId;
        inflater = LayoutInflater.from(context);
    }

    public void setDatas(List<T> datas){
        this.datas.clear();
        addDatas(datas);
    }

    public void addDatas(List<T> datas){
        this.datas.addAll(datas);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return datas.size();
    }

    @Override
    public Object getItem(int position) {
        return datas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewDataBinding dataBinding;
        if (convertView == null) {
            dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
        }else{
            dataBinding = DataBindingUtil.getBinding(convertView);
        }
        dataBinding.setVariable(variableId, datas.get(position));

        return dataBinding.getRoot();

    }
}

activity_mvvm_demo.xml ,activity的布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="shenbin.com.demo17101101.mvvp.User" />

        <variable
            name="user"
            type="User" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:onClick="@{user.onItemClick}">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="MVVM模式"
            android:gravity="center"
            android:textSize="20dp"/>

        <TextView
            android:id="@+id/tvName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.name}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.desc}" />


        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            app:img="@{user.imgUrl}"/>
        <!--app:img 为自定义属性 在User里面通过注解 绑定-->


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="下面是ListView的mvvm示例"
            android:gravity="center"/>

        <ListView
            android:id="@+id/lv"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </ListView>


    </LinearLayout>

</layout>


item_lv_mvvm.xml  ListView的item布局。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="shenbin.com.demo17101101.mvvp.User" />

        <variable
            name="user"
            type="User" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:onClick="@{user.onItemClick}">

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            app:img="@{user.imgUrl}"/>
        <!--app:img 为自定义属性 在User里面通过注解 绑定-->


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tvName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{user.name}" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{user.desc}" />


        </LinearLayout>








    </LinearLayout>

</layout>

 
//需要开启这个,然后要求Android Studio 1.5以及以上。

android{

....

//mvvm
dataBinding {
    enabled true
}

}


 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值