首先看activity_main.xml中的代码:
并且给LinearLayout设置了点击事件,和将resImgId设置到ImageView的属性android:src="@{resImgId}"。
再看看MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
Custom binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,
R.layout.activity_main);
binding.setClick(this);
}
public void click(View view) {
binding.setResImgId(R.drawable.ic_launcher);
}
}
自定义属性
默认的android命名空间下,我们会发现并不是所有的属性都能直接通过data binding进行设置,比如margin,padding,还有自定义View的各种属性。
遇到这些属性,我们就需要自己去定义它们的绑定方法。
Setter
就像Data Binding会自动去查找get方法一下,在遇到属性绑定的时候,它也会去自动寻找对应的set方法。
不懂的可以参考http://blog.zhaiyifan.cn/2016/07/06/android-new-project-from-0-p8/,这篇文章的自定义属性,Setter,和BindingMethods等。
public class ImageViewAttrAdapter {
@BindingAdapter("android:src")
public static void setSrc(ImageView view, Bitmap bitmap) {
view.setImageBitmap(bitmap);
}
@BindingAdapter("android:src")
public static void setSrc(ImageView view, int resId) {
view.setImageResource(resId);
}
}
binding.setResImgId(R.drawable.ic_launcher);
public class Custom extends android.databinding.ViewDataBinding
public void setResImgId(int resImgId) {
this.mResImgId = resImgId;
synchronized(this) {
mDirtyFlags |= 0x2L;
}
super.requestRebind();
}
/**
* @hide
*/
protected void requestRebind() {
synchronized (this) {
if (mPendingRebind) {
return;
}
mPendingRebind = true;
}
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
// Nested so that we don't get a lint warning in IntelliJ
if (!mRoot.isAttachedToWindow()) {
// Don't execute the pending bindings until the View
// is attached again.
mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
return;
}
}
executePendingBindings();
}
};
public void executePendingBindings() {
if (mIsExecutingPendingBindings) {
requestRebind();
return;
}
if (!hasPendingBindings()) {
return;
}
mIsExecutingPendingBindings = true;
mRebindHalted = false;
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBIND, null);
// The onRebindListeners will change mPendingHalted
if (mRebindHalted) {
mRebindCallbacks.notifyCallbacks(this, HALTED, null);
}
}
if (!mRebindHalted) {
executeBindings();
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
}
}
mIsExecutingPendingBindings = false;
}
/**
* @hide
*/
protected abstract void executeBindings();
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
android.view.View.OnClickListener androidViewViewOnCli = null;
int resImgId = mResImgId;
android.graphics.Bitmap bitmap = mBitmap;
org.loader.app4.MainActivity click = mClick;
java.lang.String nameStu = null;
org.loader.app4.Student stu = mStu;
if ((dirtyFlags & 0x22L) != 0) {
// read resImgId~
resImgId = resImgId;
}
if ((dirtyFlags & 0x24L) != 0) {
// read bitmap~
bitmap = bitmap;
}
if ((dirtyFlags & 0x28L) != 0) {
// read click~
click = click;
if (click != null) {
// read android.view.View.OnClickListener~click~~click
androidViewViewOnCli = (((mAndroidViewViewOnCl == null) ? (mAndroidViewViewOnCl = new OnClickListenerImpl()) : mAndroidViewViewOnCl).setValue(click));
}
}
if ((dirtyFlags & 0x31L) != 0) {
// read stu~
stu = stu;
updateRegistration(0, stu);
if (stu != null) {
// read name~.~stu~
nameStu = stu.getName();
}
}
// batch finished
if ((dirtyFlags & 0x22L) != 0) {
// api target 1
重点: org.loader.app4.ImageViewAttrAdapter.setSrc(this.imageView, resImgId);
}
if ((dirtyFlags & 0x28L) != 0) {
// api target 1
this.mboundView1.setOnClickListener(androidViewViewOnCli);
}
if ((dirtyFlags & 0x31L) != 0) {
// api target 1
this.mboundView1.setText(nameStu);
}
if ((dirtyFlags & 0x24L) != 0) {
// api target 1
org.loader.app4.ImageViewAttrAdapter.setSrc(this.mboundView2, bitmap);
}
}
org.loader.app4.ImageViewAttrAdapter.setSrc(this.imageView, resImgId);
可以看到最终调用了静态方法ImageViewAttrAdapter.setSrc(this.imageView, resImgId)方法了。
没有纠结细节部分,只是简单的分析整个调用过程。
总结:(1)android:src="@{resImgId}",会根据resImgId生成binding的setResImgId(int resId)方法。
(2)@BindingAdapter({"android:src"}),最终生成了相关的代码中,binding的setResImgId(int resId)会调用这个静态setSrc(ImageView view, int resId)方法
(分析过程如上)。
@BindingAdapter({"android:src"})
public static void setSrc(ImageView view, int resId) {
view.setImageResource(resId);
}