使用Data Binding构建MVVM应用程序

Data Binding是Google I/O大会上官方推介的,官方原生支持 MVVM 模型可以让我们更快速更好的构建代码框架。

Data Binding 性能

在Data Binding前已经有像RoboGuice、ButterKnife 这样的依赖注入框架,那么为什么要使用Data Binding?
1、Data Binding可以使代码更加干净优雅,使你的工作更加简单
首先再也不用findViewById,一些依赖注入框架像ButterKnife可以很漂亮的帮你绑定资源像这样@Bind(R.id.title) TextView title;,但是控件一多还是有非常多的绑定,
而Data Binding可以更进一步的帮你减少不必要的代码像这样mBinding.setUser(user);
2、Data Binding性能
若是findViewById,实际上是对所有子view都遍历了一遍,而每次findViewById都去遍历一遍。而Data Binding可以做到编译时就知道对应的view,只需遍历布局层次一次,就可以收集到所有的 View。
若是依赖注入的框架,我们知道数据绑定这类库是缓慢的,而Data Binding在性能方面是零反射,即一切都发生在编译期。

Data Binding 使用

确保 Android 的 Gradle 插件版本不低于 1.5.0
修改对应模块(Module)的 build.gradle:

1
2
3
4
5
6
android {
....
dataBinding {
enabled = true
}
}

Data Binding 创建

默认会根据xml文件名生成Data Binding类(会转换为首字母大写并添加Binding后缀)
若为Activity

1
2
3
4
5
6
7
8
9
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
//or
//MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
User user = new User("Test", "User");
binding.setUser(user);
}

若为fragment

1
2
3
4
5
6
7
private FragmentNotificationBinding mBinding;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_notification, container, false);
mBinding.setNotification(notification);
return mBinding.getRoot();
}

若为Custom View

1
2
3
4
5
6
7
8
9
10
11
12
private LayoutCameraStatusBinding mBinding;
public CameraStatusView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
mContext = context;
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.layout_camera_status, this, true);
}
public void initCameraStatus(CameraStatus cameraStatus) {
mBinding.setStatus(cameraStatus);
}

若为Recyclerview/ListView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//in ChatItemLeftViewHolder class
public class ChatItemLeftViewHolder extends RecyclerView.ViewHolder {
public final RecyclerviewItemChatLeftBinding binding;
public ChatItemLeftViewHolder(View rootView) {
super(rootView);
binding = DataBindingUtil.bind(rootView);
}
}
//in adapter
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_SENDER) {
RecyclerviewItemChatLeftBinding binding = RecyclerviewItemChatLeftBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ChatItemLeftViewHolder(binding.getRoot());
} else {
RecyclerviewItemChatRightBinding binding = RecyclerviewItemChatRightBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ChatItemRightViewHolder(binding.getRoot());
}
//or
//ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Message message = messages.get(position);
if (holder instanceof ChatItemLeftViewHolder) {
((ChatItemLeftViewHolder) holder).binding.setMessage(message);
} else if (holder instanceof ChatItemRightViewHolder) {
((ChatItemRightViewHolder) holder).binding.setMessage(message);
}
}

其他用法参见官方文档

Data Binding 构建MVVM应用程序

MVVM(Model-View-ViewModel)

Model

1
2
3
4
5
6
//bean
public class CameraStatus {
//此处省略
}
public class CameraStatusModel {
}

View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="status"
type="com.royole.focuslib.live.CameraStatus" />
<import type="android.view.View" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:gravity="center_vertical"
android:orientation="horizontal">
//此处省略
<TextView
android:id="@+id/tv_sd_remain_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(status.remainCount)}"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/white" />
<ImageView
android:id="@+id/iv_self_timer"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:src="@mipmap/camera_status_self_timer"
android:visibility="@{status.isSelfTimer ? View.VISIBLE : View.GONE}" />
</LinearLayout>
</layout>

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class CameraStatusView extends LinearLayout {
private final String TAG = CameraStatusView.this.getClass().getSimpleName();
private Context mContext;
private LayoutCameraStatusBinding mBinding;
public CameraStatusView(Context context) {
super(context);
init(context);
}
public CameraStatusView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraStatusView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mContext = context;
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.layout_camera_status, this, true);
}
public void initCameraStatus(CameraStatus cameraStatus) {
mBinding.setStatus(cameraStatus);
}
}

Data Binding 高级使用

后续进行说明…