学习android的MVVM设计模式
来源:互联网 发布:湖南农大网络教学平台 编辑:程序博客网 时间:2024/05/22 09:05
最近更迷上了国外的技术网站,结合一些国内好的网站Get新技术。
MVVM(Model-View-ViewModel)是MVP的升级篇,厉害了我的哥。
“关键在于View和Model的双向绑定,当View有用户输入后,ViewModel通知Model更新数据,同理Model数据更新之后,ViewModel通知View更新”--摘自郭霖文章原话
我自己写些博客不是很好,只是借鉴别人的文章get新技术,然后记录下来。MVVM的知识来自http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236908&idx=1&sn=9e53f42e18a81795ef0cfe6fe3959ec2&scene=24&srcid=0910cK3vXJpNzY0CO28i1Qhs#wechat_redirect
国外原文地址:
https://developer.android.com/topic/libraries/data-binding/index.html
1、在build.gradle的android{}中配置
dataBinding{ enabled = true}2、新建一个User类
/** * Created by GuoMeng on 2017/3/14. * Description */public class User { private String name; private String firstName; private String lastName; private boolean isStudent; public User(String name, String firstName, String lastName, boolean isStudent) { this.name = name; this.firstName = firstName; this.lastName = lastName; this.isStudent = isStudent; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public boolean isStudent() { return isStudent; } public void setStudent(boolean student) { isStudent = student; }}3、在activity_main.xml文件改为
提示:注解很重要
<?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"> <!-- name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置 --> <!-- 写法1 --> <!-- 声明了需要用到的user对象 --> <data> <import type="com.gm.mvvmdemo.User"/><!-- type指定路径 --> <variable name="user" type="User" /> </data> <!-- 写法1 存在同名UserEntity时,设置别名(注意alias要与type一致) --> <!-- <data> <import type="com.gm.mvvmdemo.User" alias="MUser"/> <import type="com.gm.mvvmdemo.others.User" alias="OUser"/> <variable name="user" type="MUser"/> <variable name="oUser" type="OUser"/> </data>--> <!-- 写法2 --> <!--<data> <variable name="user" type="com.gm.mvvmdemo.User"/> </data>--> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" android:textSize="20sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}" android:textSize="25sp"/> </LinearLayout></layout>4、默认情况下,在MainActivity中可以调用ActivityMainBinding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);User user = new User("", "开发者", "程序员", true);binding.setUser(user);运行app,数据就会显示在控件上。也可不用默认创建的ActivityMainBinding,那就在activity_main.xml的data 标签添加class属性,比如:
<data class="MainBinding"> ...</data>5、比如在activity_main.xml中的两个控件用的都引用了同名的User类,那么可以设置别名,再引用
<!-- 写法1 存在同名UserEntity时,设置别名(注意alias要与type一致) --> <data> <import type="com.gm.mvvmdemo.User" alias="MUser"/> <import type="com.gm.mvvmdemo.others.User" alias="OUser"/> <variable name="user" type="MUser"/> <variable name="oUser" type="OUser"/> </data>控件调用都一样使用name属性的命名取引用
6、如何查看ActivityMainBinding?需要反编译app,才可以看到ActivityMainBinding类以及默认对应创建的setUser方法
/** * ActivityMainBinding自动生成的,可以通过反编译查看setUser方法 * 下面的setUser方法: * public void setUser(User paramUser) { * this.mUser = paramUser; * try{ * this.mDirtyFlags = (1L|this.mDirtyFlags); * super.requestRebind(); * return; * } * finally{} * } * */7、消除空指针
* 消除空指针* 自动生成的DataBinding代码会检查null,避免出现NullPointException* 例如在表达式中 @{user.firstName}如果user == null 那么会为 user.firstName 设置默认值null* 而不会导致程序崩溃(基本类型将赋予默认值如 int为0,引用类型都会赋值null)*8、比如设置控件的显示隐藏,需要导入
<import type="android.view.View"/>
<!-- 注意:只要是在Java中需要导入包的类,这边都需要导入,如:Map、ArrayList等,不过 java.lang 包里的类是可以不用导包的。 -->
一个xml中只能存在一个data,否则会报错
9、三元运算<!-- 三元运算(需用"")--><!-- android:text="@{user.student ? "学生":"工人"}" --><!-- visibility需要导包,因此在data中添加android.view.View。这里还需注意只能存在一个data 否则报错--><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.student ? user.firstName:user.lastName}" android:textSize="25sp"/><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.student ? user.firstName:user.lastName}" android:visibility="@{user.student ? View.VISIBLE:View.GONE}" android:background="#6ddc5a"// 这里使用背景颜色验证下可行性 android:textSize="25sp"/>10、非
<!-- ?? 除了常用的操作法,另外还提供了一个 null 的合并运算符号 ??,这是一个三目运算符的简便写法 "user.firstName" ?? "user.lastName" 相当于 "user.firstName" != null ? "user.firstName":"user.lastName"android:text="@{user.name ?? user.firstName}"没有效果,不可行android:text="@{user.name !=null ? user.firstName:user.lastName}" --><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name !=null ? user.firstName:user.lastName}" android:textSize="25sp"/>11、
<!-- 所支持的操作符如下: 数学运算符 + - / * % 字符串拼接 + 逻辑运算 && || 二进制运算 & | ^ 一元运算符 + - ! ~ 位运算符 >> >>> << 比较运算符 == > < >= <= instanceof Grouping () 文字 - character, String, numeric, null 类型转换 cast 方法调用 methods call 字段使用 field access 数组使用 [] Arrary access 三元运算符 ? -->12、这里加载图片的我设置失败,有待研究
13、点击事件
(1)在MainActivity类中声明onClick方法(类似平时实现监听接口)
public void onClick(View view) { switch (view.getId()) { case R.id.btn_one: Log.d("execute", "按钮one的点击事件"); break; case R.id.btn_two: Log.d("execute", "按钮two的点击事件"); break; }}(2)在activity_main.xml的data中添加
<variable name="mainActivity" type="com.gm.mvvmdemo.MainActivity"/>(3)绑定监听
<Button android:id="@+id/btn_one" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮1" android:onClick="@{mainActivity.onClick}"/><Button android:id="@+id/btn_two" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮2" android:onClick="@{mainActivity.onClick}"/>(4)最后在MainActivity中调用方法
binding.setMainActivity(this);14、外部类实现监听
(1)先新建一个MyHandler类
public class MyHandler { public void onClick(View view) { Log.d("execute", "外部的点击事件"); }}(2)同样添加
<variable name="handle" type="com.gm.mvvmdemo.MyHandler"/>(3)然后绑定
<Button android:id="@+id/btn_three" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮3" android:onClick="@{handle.onClick}"/>(4)最后调用
binding.setHandle(new MyHandler());
15、调用类成员变量
// public 或 public static可行,private修饰的不能直接在xml中调用,只能通过共有方法调用public String name = "Hello , Coder";
// 若是上面改为静态共有的可以直接
//android:text="@{mainActivity.name}"
共有方法
public String getTheName() { String name = this.name; return name;}给控件设置内容
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{mainActivity.getTheName()}"/>
16、数据改变时更新UI,ActivityMainBinding、User改为全局的,再调用delay方法
private void delay() { new Handler().postDelayed(new Runnable() { @Override public void run() { user.setFirstName("haha"); binding.setUser(user); } },2000);}17、继承BaseObservable更加方便,项目中创建了两个User类
目前的User类是另一个类,正好回顾下使用别名
(1)继承
public class User extends BaseObservable{(2)刷新
public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR._all);}
public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR._all);}(3)
<import type="com.gm.mvvmdemo.others.User" alias="OUser"/>
<variable name="oUser" type="OUser"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{oUser.firstName}"/>
(4)测试效果,这里我休眠3秒
final com.gm.mvvmdemo.others.User oUser = new com.gm.mvvmdemo.others.User("", "大哥", "小弟", true);binding.setOUser(oUser);new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); oUser.setFirstName("太阳"); } catch (InterruptedException e) { e.printStackTrace(); } }}).start();
18、更方便
* Data Binding的开发者贴心得为我们准备了一系列的 ObservableField,包括: ObservableBoolean,* ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat,* ObservableDouble 以及 ObservableParcelable
(1)新建一个User2类
public class User2 { public final ObservableField<String> firstName = new ObservableField<>(); public final ObservableField<String> lastName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(); public final ObservableBoolean isStudent = new ObservableBoolean();}
(2)同样导包+引用
<import type="com.gm.mvvmdemo.User2"/>
<variable name="user2" type="User2"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user2.firstName+user2.lastName+String.valueOf(user2.age)}"/>这里我自己尝试是否可以直接拼接在一起(3)同样实现数据绑定
User2 user2 = new User2();binding.setUser2(user2);user2.firstName.set("郭");user2.lastName.set("孟");user2.age.set(24);user2.isStudent.set(true);也可与17、(4)设置等待3秒后改变值
19、ObservableArrayMap和ObservableArrayList不能使用,我也不知到为什么
提示:xml文件也只能存在一个父布局
20、RecyclerView的使用
(1)添加RecyclerView控件
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/>(2)自定义adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder>{ private List<User2> mData = new ArrayList<>(); public MyAdapter(List<User2> data) { this.mData = data; } @Override public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) { return MyHolder.create( LayoutInflater.from(parent.getContext()), parent); } @Override public void onBindViewHolder(MyHolder holder, int position) { holder.bindTo(mData.get(position)); } @Override public int getItemCount() { if (mData == null) { return 0; } return mData.size(); } public static class MyHolder extends RecyclerView.ViewHolder{ private UserItemBinding mBinding; static MyHolder create(LayoutInflater inflater, ViewGroup parent) { UserItemBinding binding = UserItemBinding.inflate(inflater, parent, false); return new MyHolder(binding); } private MyHolder(UserItemBinding binding) { super(binding.getRoot()); this.mBinding = binding; } public void bindTo(User2 user) { mBinding.setUser2(user); mBinding.executePendingBindings(); } }}(3)setAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);LinearLayoutManager layoutManager = new LinearLayoutManager( this, LinearLayoutManager.VERTICAL, false);recyclerView.setLayoutManager(layoutManager);recyclerView.setAdapter(new MyAdapter(data));(4)user_item.xml
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user2" type="com.gm.mvvmdemo.User2"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user2.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="."/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user2.lastName}"/> <View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{user2.age+""}'/> </LinearLayout></layout>21、前面自己也有测试引用
比如设置textview时可以'@{user.age+""}'或者是"@{String.valueOf(user.age)}" ,需要自己细心,前面我自己有测试了
- 学习android的MVVM设计模式
- android设计模式MVVM
- Android DataBinding(MVVM设计模式)
- android中mvvm设计模式
- Android设计模式之MVVM
- Android架构设计---关于MVVM模式的探讨
- Android架构设计---关于MVVM模式的探讨
- Android架构设计---关于MVVM模式的探讨
- android UI设计MVVM设计模式
- WPF学习系列 MVVM设计模式 一
- Android DataBinding库(MVVM设计模式)
- 【Android】DataBinding库(MVVM设计模式)
- Android DataBinding库(MVVM设计模式)
- Android DataBinding库(MVVM设计模式)
- Android DataBinding库(MVVM设计模式)
- android设计模式(MVC MVP MVVM)
- Android的MVVM模式优缺点
- Android MVVM模式的理解
- 程序员职业思考与规划 —— 程序员,杂草和大树,你选哪个?---程序员如何塑造顶端优势
- 云端大规模视频分析: MaxCompute在视觉计算中的应用
- 学习笔记——Maven实战(九)打包的技巧
- SQL Server学习笔记(一)
- 作业(sublime text插件)
- 学习android的MVVM设计模式
- Mac下adb环境配置
- innodb事务锁
- oracle数据库表锁死,杀掉session
- Hibernate JPA中@Transient、@JsonIgnoreProperties、@JsonIgnore、@JsonFormat、@JsonSerialize等注解解释
- SymPy学习之Numeric Computation
- CentOS iso本地源配置
- 对象克隆
- 关于界面界面流畅度的优化和runloop等的理解