数据绑定(Data Binding)在布局文件中实现数据绑定申明,使数据的变化引起视图的自动更新,减少逻辑代码,从而在Android中方便地实现MVVM的开发模式。
vlc for android中用到了数据绑定(databinding),下面看一个例子:
一、布局文件
list_item.xml中布局是这样的:
name="holder"
type="org.videolan.vlc.gui.HistoryAdapter.ViewHolder"/>
name="media"
type="MediaWrapper"/>
name="position"
type="int"/>
android:id="@+id/layout_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:clickable="true"
android:onClick="@{holder.onClick}">
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@{media.type == MediaWrapper.TYPE_VIDEO ? @drawable/ic_browser_video_normal : @drawable/ic_browser_audio_normal}" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="5dip"
android:text="@{media.title}"
android:layout_gravity="center_vertical"
android:fontFamily="sans-serif-light"
android:textColor="?attr/list_title"
android:textSize="16sp"
android:singleLine="true"
android:scrollHorizontally="true"/>
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:text="@{media.artist}"
android:fontFamily="sans-serif-light"
android:textColor="?attr/list_subtitle"
android:singleLine="true"
android:ellipsize="start"
android:visibility="@{media.artist == null ? View.GONE : View.VISIBLE}"/>
我们可以看到支持 Data Binding的布局文件和以前的布局文件不一样,它的跟节点不再是一个ViewGroup,而是layout,并且多了一个data节点。在上面这个例子中定义了3个变量:holder,media,position。
二、POJO文件:
构建工具gradle会自动构建一个中间文件ListItemBinding.java,该文件存在于vlc-android/build/intermediates/classes/vanillaARMv7/debug/org/videolan/vlc/databinding这个目录下,具体代码如下:
package org.videolan.vlc.databinding;
import org.videolan.vlc.R;
import org.videolan.vlc.BR;
import android.view.View;
public class ListItemBinding extends android.databinding.ViewDataBinding {
private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;
private static final android.util.SparseIntArray sViewsWithIds;
static {
sIncludes = null;
sViewsWithIds = null;
}
// views
public final android.widget.ImageView icon;
public final android.widget.LinearLayout layoutItem;
public final android.widget.TextView subtitle;
public final android.widget.TextView title;
// variables
private org.videolan.vlc.gui.HistoryAdapter.ViewHolder mHolder;
private org.videolan.vlc.media.MediaWrapper mMedia;
// values
// listeners
private OnClickListenerImpl mAndroidViewViewOnCl;
// Inverse Binding Event Handlers
public ListItemBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
super(bindingComponent, root, 0);
final Object[] bindings = mapBindings(bindingComponent, root, 4, sIncludes, sViewsWithIds);
this.icon = (android.widget.ImageView) bindings[1];
this.icon.setTag(null);
this.layoutItem = (android.widget.LinearLayout) bindings[0];
this.subtitle = (android.widget.TextView) bindings[3];
this.subtitle.setTag(null);
this.title = (android.widget.TextView) bindings[2];
this.title.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
}
@Override
public void invalidateAll() {
synchronized(this) {
mDirtyFlags = 0x8L;
}
requestRebind();
}
@Override
public boolean hasPendingBindings() {
synchronized(this) {
if (mDirtyFlags != 0) {
return true;
}
}
return false;
}
public boolean setVariable(int variableId, Object variable) {
switch(variableId) {
case BR.holder :
setHolder((org.videolan.vlc.gui.HistoryAdapter.ViewHolder) variable);
return true;
case BR.media :
setMedia((org.videolan.vlc.media.MediaWrapper) variable);
return true;
case BR.position :
return true;
}
return false;
}
public void setPosition(int position) {
// not used, ignore
}
public int getPosition() {
return 0;
}
public void setHolder(org.videolan.vlc.gui.HistoryAdapter.ViewHolder holder) {
this.mHolder = holder;
synchronized(this) {
mDirtyFlags |= 0x1L;
}
super.requestRebind();
}
public org.videolan.vlc.gui.HistoryAdapter.ViewHolder getHolder() {
return mHolder;
}
public void setMedia(org.videolan.vlc.media.MediaWrapper media) {
this.mMedia = media;
synchronized(this) {
mDirtyFlags |= 0x2L;
}
super.requestRebind();
}
public org.videolan.vlc.media.MediaWrapper getMedia() {
return mMedia;
}
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
}
return false;
}
......
}
这个java文件有点像java bean文件,3个变量的getter和setter方法。
三、绑定数据
怎么使用的呢?可以看vlc-android\src\org\videolan\vlc\gui\HistoryAdapter.java,有如下代码:
ListItemBinding binding;
public ViewHolder(View itemView) {
super(itemView);
binding = DataBindingUtil.bind(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final MediaWrapper media = mMediaList.get(position);
holder.binding.setMedia(media);
holder.binding.setHolder(holder);
}