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 }
}