源码版本:Android10
在上一篇 jetpack之数据绑定的源码解读(一)中介绍了DataBinding的基本原理,这篇文章主要是讲@InverseBindingAdapter以及是如何实现双向绑定的。一、Demo源码
1.1 activity_recycler_view.xml源码
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="refresh"
type="com.study.jetpackstudykotlin.databinding.bean.Refresh" />
</data>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/srl"
refreshing="@={refresh.swipeRefreshViewRefreshing}"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".databinding.RecyclerViewActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/bt"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>
1.2 RecyclerViewActivity源码
package com.study.jetpackstudykotlin.databinding
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.study.jetpackstudykotlin.R
import com.study.jetpackstudykotlin.databinding.adapter.RvAdapter
import com.study.jetpackstudykotlin.databinding.bean.Refresh
import com.study.jetpackstudykotlin.databinding.bean.User
class RecyclerViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view)
val binding = DataBindingUtil.setContentView<ActivityRecyclerViewBinding>(
this,
R.layout.activity_recycler_view
)
val refresh = Refresh()
binding.refresh = refresh
binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
var arrayList = arrayListOf<User>()
for (j in 0..100) {
arrayList.add(User("简单$j", "粗暴$j"))
}
binding.rv.adapter = RvAdapter(this, arrayList)
binding.bt.setOnClickListener {
Log.e("refresh::", "当前binding.refresh值为Activity" + refresh.swipeRefreshViewRefreshing.get())
//修改刷新状态值
refresh.swipeRefreshViewRefreshing.set(false)
}
}
}
1.3 ViewAdapter源码
package com.study.jetpackstudykotlin.databinding.viewAdapter;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.databinding.BindingAdapter;
import androidx.databinding.BindingConversion;
import androidx.databinding.InverseBindingAdapter;
import androidx.databinding.InverseBindingListener;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
public class ViewAdapter {
@BindingAdapter(value = {"imgContent"})
public static void loadImage(AppCompatImageView imageView, final String content) {
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), content, Toast.LENGTH_SHORT).show();
}
});
}
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
return new ColorDrawable(color);
}
//===================SwipeRefreshLayout双向绑定的具体实现===================
@InverseBindingAdapter(attribute = "refreshing", event = "refreshingAttrChanged")
public static boolean isRefreshing(SwipeRefreshLayout view) {
return view.isRefreshing();
}
//InverseBindingListener refreshingAttrChanged是由apt帮忙生成的
@BindingAdapter(value = {"refreshingAttrChanged"}, requireAll = false)
public static void setOnRefreshListener(final SwipeRefreshLayout view,
final InverseBindingListener refreshingAttrChanged) {
if (refreshingAttrChanged != null) {
//给view设置刷新监听
view.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshingAttrChanged.onChange();
Log.e("refresh::", "当前binding.refresh值为" + view.isRefreshing());
}
});
}
}
@BindingAdapter("refreshing")
public static void setRefreshing(SwipeRefreshLayout view, boolean refreshing) {
//两者不相同,才去刷新SwipeRefreshLayout
if (refreshing != view.isRefreshing()) {
view.setRefreshing(refreshing);
}
}
}
二、源码分析
这里使用SwipeRefreshLayout来作为实现双向绑定的示例,xml文件中refreshing="@={refresh.swipeRefreshViewRefreshing}",@=是实现双向绑定的关键条件之一
com.study.jetpackstudykotlin.databinding.ActivityRecyclerViewBindingImpl源码如下所示:
package com.study.jetpackstudykotlin.databinding;
import com.study.jetpackstudykotlin.R;
import com.study.jetpackstudykotlin.BR;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.View;
@SuppressWarnings("unchecked")
public class ActivityRecyclerViewBindingImpl extends ActivityRecyclerViewBinding {
@Nullable
private static final androidx.databinding.ViewDataBinding.IncludedLayouts sIncludes;
@Nullable
private static final android.util.SparseIntArray sViewsWithIds;
static {
sIncludes = null;
sViewsWithIds = new android.util.SparseIntArray();
sViewsWithIds.put(R.id.rv, 1);
sViewsWithIds.put(R.id.bt, 2);
}
// views
// variables
// values
// listeners
// Inverse Binding Event Handlers,生产双向绑定的监听类
private androidx.databinding.InverseBindingListener srlrefreshingAttrChanged = new androidx.databinding.InverseBindingListener() {
@Override
public void onChange() {
// Inverse of refresh.swipeRefreshViewRefreshing.get()
// is refresh.swipeRefreshViewRefreshing.set((boolean) callbackArg_0)
//通过调用isRefreshing方法,获取SwipeRefreshLayout刷新状态的回调值
boolean callbackArg_0 = com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.isRefreshing(srl);
// localize variables for thread safety
// refresh != null
boolean refreshJavaLangObjectNull = false;
// refresh.swipeRefreshViewRefreshing != null
boolean refreshSwipeRefreshViewRefreshingJavaLangObjectNull = false;
// refresh 进入页面的首次状态值
com.study.jetpackstudykotlin.databinding.bean.Refresh refresh = mRefresh;
// refresh.swipeRefreshViewRefreshing.get()
boolean refreshSwipeRefreshViewRefreshingGet = false;
// refresh.swipeRefreshViewRefreshing
androidx.databinding.ObservableBoolean refreshSwipeRefreshViewRefreshing = null;
refreshJavaLangObjectNull = (refresh) != (null);
if (refreshJavaLangObjectNull) {
//获取xml文件中操作SwipeRefreshLayout刷新状态的对象
refreshSwipeRefreshViewRefreshing = refresh.getSwipeRefreshViewRefreshing();
refreshSwipeRefreshViewRefreshingJavaLangObjectNull = (refreshSwipeRefreshViewRefreshing) != (null);
if (refreshSwipeRefreshViewRefreshingJavaLangObjectNull) {
//将改变之后的刷新状态值交给Activity里面refreshSwipeRefreshViewRefreshing,从而实现双向绑定
refreshSwipeRefreshViewRefreshing.set(((boolean) (callbackArg_0)));
}
}
}
};
public ActivityRecyclerViewBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
}
private ActivityRecyclerViewBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
super(bindingComponent, root, 1
, (android.widget.Button) bindings[2]
, (androidx.recyclerview.widget.RecyclerView) bindings[1]
, (androidx.swiperefreshlayout.widget.SwipeRefreshLayout) bindings[0]
);
this.srl.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
}
@Override
public void invalidateAll() {
synchronized(this) {
mDirtyFlags = 0x4L;
}
requestRebind();
}
@Override
public boolean hasPendingBindings() {
synchronized(this) {
if (mDirtyFlags != 0) {
return true;
}
}
return false;
}
@Override
public boolean setVariable(int variableId, @Nullable Object variable) {
boolean variableSet = true;
if (BR.refresh == variableId) {
setRefresh((com.study.jetpackstudykotlin.databinding.bean.Refresh) variable);
}
else {
variableSet = false;
}
return variableSet;
}
public void setRefresh(@Nullable com.study.jetpackstudykotlin.databinding.bean.Refresh Refresh) {
this.mRefresh = Refresh;
synchronized(this) {
mDirtyFlags |= 0x2L;
}
notifyPropertyChanged(BR.refresh);
super.requestRebind();
}
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0 :
return onChangeRefreshSwipeRefreshViewRefreshing((androidx.databinding.ObservableBoolean) object, fieldId);
}
return false;
}
private boolean onChangeRefreshSwipeRefreshViewRefreshing(androidx.databinding.ObservableBoolean RefreshSwipeRefreshViewRefreshing, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x1L;
}
return true;
}
return false;
}
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
com.study.jetpackstudykotlin.databinding.bean.Refresh refresh = mRefresh;
boolean refreshSwipeRefreshViewRefreshingGet = false;
androidx.databinding.ObservableBoolean refreshSwipeRefreshViewRefreshing = null;
if ((dirtyFlags & 0x7L) != 0) {
if (refresh != null) {
// read refresh.swipeRefreshViewRefreshing
refreshSwipeRefreshViewRefreshing = refresh.getSwipeRefreshViewRefreshing();
}
updateRegistration(0, refreshSwipeRefreshViewRefreshing);
if (refreshSwipeRefreshViewRefreshing != null) {
// read refresh.swipeRefreshViewRefreshing.get()
refreshSwipeRefreshViewRefreshingGet = refreshSwipeRefreshViewRefreshing.get();
}
}
// batch finished
if ((dirtyFlags & 0x7L) != 0) {
// api target 1
com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.setRefreshing(this.srl, refreshSwipeRefreshViewRefreshingGet);
}
if ((dirtyFlags & 0x4L) != 0) {
// api target 1
com.study.jetpackstudykotlin.databinding.viewAdapter.ViewAdapter.setOnRefreshListener(this.srl, srlrefreshingAttrChanged);
}
}
// Listener Stub Implementations
// callback impls
// dirty flag
private long mDirtyFlags = 0xffffffffffffffffL;
/* flag mapping
flag 0 (0x1L): refresh.swipeRefreshViewRefreshing
flag 1 (0x2L): refresh
flag 2 (0x3L): null
flag mapping end*/
//end
}