问题思考
- databinding是怎么生成xml对象类呢?
- 为啥我在xml设置的tag不生效呢
- databinding如何实现数据自动刷新呢?
1. 如何生成布局对应的binding对象
我们show一波基本写法
activity_main.xml
// 通用写法
<data>
<variable
name="mainVm"
type="com.wqg.wqgdatabdingandviewmodel.MainVm" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVm.name}"
android:textSize="20sp"
tools:text="tv1"/>
<TextView
android:layout_marginTop="20dp"
tools:text="tv2"
android:textSize="20sp"
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVm.pwd}"/>
<TextView
android:layout_marginTop="20dp"
tools:text="tv3"
android:textSize="20sp"
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVm.nameF}"/>
<TextView
android:layout_marginTop="20dp"
tools:text="tv4"
android:textSize="20sp"
android:id="@+id/tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVm.pwdF}"/>
<EditText
android:id="@+id/et1"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={mainVm.name}"
android:hint="双向绑定1"/>
<EditText
android:id="@+id/et2"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={mainVm.nameF}"
android:hint="双向绑定2"/>
</LinearLayout>
编译之后,/app/build/intermediates/data_binding_layout_info_type_merge/debug/out下面拷贝生成了一份activity_main-layout.xml 从下可以看到,他会先针对所有控件都给了一个Taggets的标签,跟布局的设置tag=layout/activity_main_0,其他控件的tag=binding_数字。这就一个坑,你如果手动在xml设置这个TAG是无效的。
activity_main-layout.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout directory="layout" filePath="app/src/main/res/layout/activity_main.xml"
isBindingData="true" isMerge="false" layout="activity_main"
modulePackage="com.wqg.wqgdatabdingandviewmodel" rootNodeType="android.widget.LinearLayout">
<Variables name="mainVm" declared="true" type="com.wqg.wqgdatabdingandviewmodel.MainVm">
<location endLine="9" endOffset="60" startLine="7" startOffset="8" />
</Variables>
<Targets>
<Target tag="layout/activity_main_0" view="LinearLayout">
<Expressions />
<location endLine="68" endOffset="18" startLine="13" startOffset="4" />
</Target>
<Target id="@+id/tv1" tag="binding_1" view="TextView">
<Expressions>
<Expression attribute="android:text" text="mainVm.name">
<Location endLine="23" endOffset="40" startLine="23" startOffset="12" />
<TwoWay>false</TwoWay>
<ValueLocation endLine="23" endOffset="38" startLine="23" startOffset="28" />
</Expression>
</Expressions>
<location endLine="25" endOffset="29" startLine="19" startOffset="8" />
</Target>
<Target id="@+id/tv2" tag="binding_2" view="TextView">
<Expressions>
<Expression attribute="android:text" text="mainVm.pwd">
<Location endLine="33" endOffset="39" startLine="33" startOffset="12" />
<TwoWay>false</TwoWay>
<ValueLocation endLine="33" endOffset="37" startLine="33" startOffset="28" />
</Expression>
</Expressions>
<location endLine="33" endOffset="41" startLine="26" startOffset="8" />
</Target>
<Target id="@+id/tv3" tag="binding_3" view="TextView">
<Expressions>
<Expression attribute="android:text" text="mainVm.nameF">
<Location endLine="42" endOffset="41" startLine="42" startOffset="12" />
<TwoWay>false</TwoWay>
<ValueLocation endLine="42" endOffset="39" startLine="42" startOffset="28" />
</Expression>
</Expressions>
<location endLine="42" endOffset="43" startLine="35" startOffset="8" />
</Target>
<Target id="@+id/tv4" tag="binding_4" view="TextView">
<Expressions>
<Expression attribute="android:text" text="mainVm.pwdF">
<Location endLine="50" endOffset="40" startLine="50" startOffset="12" />
<TwoWay>false</TwoWay>
<ValueLocation endLine="50" endOffset="38" startLine="50" startOffset="28" />
</Expression>
</Expressions>
<location endLine="50" endOffset="42" startLine="43" startOffset="8" />
</Target>
<Target id="@+id/et1" tag="binding_5" view="EditText">
<Expressions>
<Expression attribute="android:text" text="mainVm.name">
<Location endLine="57" endOffset="41" startLine="57" startOffset="12" />
<TwoWay>true</TwoWay>
<ValueLocation endLine="57" endOffset="39" startLine="57" startOffset="29" />
</Expression>
</Expressions>
<location endLine="58" endOffset="33" startLine="52" startOffset="8" />
</Target>
<Target id="@+id/et2" tag="binding_6" view="EditText">
<Expressions>
<Expression attribute="android:text" text="mainVm.nameF">
<Location endLine="65" endOffset="42" startLine="65" startOffset="12" />
<TwoWay>true</TwoWay>
<ValueLocation endLine="65" endOffset="40" startLine="65" startOffset="29" />
</Expression>
</Expressions>
<location endLine="66" endOffset="33" startLine="60" startOffset="8" />
</Target>
</Targets>
</Layout>
以上我们看到了databinding重新拷贝了一份xml,为啥?其实很好理解,android 本身不知道<layout>这个标签的,这玩意是databinding玩的。相当它要解析原来xml data标签和我们真正的布局。
接着我们看下如何生成我们要的databinding布局对象
class MainActivity : AppCompatActivity() {
private val mVm = MainVm()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) //从这里开始玩
binding.mainVm = mVm
mVm.name = "我是name 1"
mVm.pwd = "我是pwd 1"
mVm.nameF.set("我是nameF 1")
mVm.pwdF.set("我是pwdF 1")
}
}
class MainVm: ViewModel() {
var name: String? = null
var pwd : String? = null
// 第二种方式
val nameF : ObservableField<String> by lazy { ObservableField<String>() }
val pwdF : ObservableField<String> by lazy { ObservableField<String>() }
val nameF2 = ObservableField("我是双向绑定nameF2")
val pwdF2 = ObservableField("我是双向绑定pwdF2")
//-------------------------------------
var count = ObservableField(0)
}
开始跟上DataBindingUtil.java下面的setContentView了
public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,int layoutId, @Nullable DataBindingComponent bindingComponent) {
// 回到原来的setcontentView
activity.setContentView(layoutId);
View decorView = activity.getWindow().getDecorView();
ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
// 重点关注
return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}
private static <T extends ViewDataBinding> T bindToAddedViews(DataBindingComponent component,
ViewGroup parent, int startChildren, int layoutId) {
final int endChildren = parent.getChildCount();
final int childrenAdded = endChildren - startChildren;
if (childrenAdded == 1) {
final View childView = parent.getChildAt(endChildren - 1);
return bind(component, childView, layoutId);
} else {
final View[] children = new View[childrenAdded];
for (int i = 0; i < childrenAdded; i++) {
children[i] = parent.getChildAt(i + startChildren);
}
// 核心代码
return bind(component, children, layoutId);
}
}
static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View[] roots,int layoutId) {
// 核心代码
return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
}
先看看sMapper 这个是什么鬼东西,再看看getDataBinder到底是干啥的
//DataBindingUtil.java
private static DataBinderMapper sMapper = new DataBinderMapperImpl();
//再看看DataBinderMapperImpl.java
public class DataBinderMapperImpl extends MergedDataBinderMapper {
DataBinderMapperImpl() {
//是不是有熟悉的味道了,看到我们自己的包名了
addMapper(new com.wqg.wqgdatabdingandviewmodel.DataBinderMapperImpl());
}
}
回到我们之前的问题,sMapper.getDataBinder(bindingComponent, roots, layoutId);自己根据接口实现,最后回到MergedDataBinderMapper.java下面的getDataBinder
public class MergedDataBinderMapper extends DataBinderMapper {
@Override
public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
int layoutId) {
// 会通过遍历的方式,前面我们也看到了这个子对象DataBinderMapperImpl
for(DataBinderMapper mapper : mMappers) {
ViewDataBinding result = mapper.getDataBinder(bindingComponent, view, layoutId);
if (result != null) {
return result;
}
}
if (loadFeatures()) {
return getDataBinder(bindingComponent, view, layoutId);
}
return null;
}
}
public class DataBinderMapperImpl extends DataBinderMapper {
private static final int LAYOUT_ACTIVITYMAIN = 1;
private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(1);
static {
INTERNAL_LAYOUT_ID_LOOKUP.put(com.wqg.wqgdatabdingandviewmodel.R.layout.activity_main, LAYOUT_ACTIVITYMAIN);
}
@Override
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
if(localizedLayoutId > 0) {
final Object tag = view.getTag();
if(tag == null) {
throw new RuntimeException("view must have a tag");
}
switch(localizedLayoutId) {
case LAYOUT_ACTIVITYMAIN: {
// 看到这个鬼东西了吗?是不是有点熟悉的味道,没错,就是那味,我们前面生成根布局给它设置对应的tag
if ("layout/activity_main_0".equals(tag)) {
return new ActivityMainBindingImpl(component, view);
}
throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
}
}
}
return null;
}
从上面的代码,我们找到了ActivityMainBindingImpl。接着我们看下它干了啥。
public class ActivityMainBindingImpl extends ActivityMainBinding {
public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
// mapBindings重点代码
this(bindingComponent, root, mapBindings(bindingComponent, root, 7, sIncludes, sViewsWithIds));
}
// 之前xml的tag全部都给弄成null了,所有的控件都存到了bindings数组
private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
super(bindingComponent, root, 2
, (android.widget.EditText) bindings[5]
, (android.widget.EditText) bindings[6]
, (android.widget.TextView) bindings[1]
, (android.widget.TextView) bindings[2]
, (android.widget.TextView) bindings[3]
, (android.widget.TextView) bindings[4]
);
this.et1.setTag(null);
this.et2.setTag(null);
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
this.tv1.setTag(null);
this.tv2.setTag(null);
this.tv3.setTag(null);
this.tv4.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
}
// 控件都存到数组里面
protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
Object[] bindings = new Object[numBindings];
mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
return bindings;
}
private static void mapBindings(DataBindingComponent bindingComponent, View view,
Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
boolean isRoot) {
final int indexInIncludes;
final ViewDataBinding existingBinding = getBinding(view);
if (existingBinding != null) {
return;
}
Object objTag = view.getTag();
final String tag = (objTag instanceof String) ? (String) objTag : null;
boolean isBound = false;
if (isRoot && tag != null && tag.startsWith("layout")) {
final int underscoreIndex = tag.lastIndexOf('_');
if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) {
final int index = parseTagInt(tag, underscoreIndex + 1);
if (bindings[index] == null) {
bindings[index] = view;
}
indexInIncludes = includes == null ? -1 : index;
isBound = true;
} else {
indexInIncludes = -1;
}
} else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) {
int tagIndex = parseTagInt(tag, BINDING_NUMBER_START);
if (bindings[tagIndex] == null) {
bindings[tagIndex] = view;
}
isBound = true;
indexInIncludes = includes == null ? -1 : tagIndex;
} else {
// Not a bound view
indexInIncludes = -1;
}
if (!isBound) {
final int id = view.getId();
if (id > 0) {
int index;
if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0 &&
bindings[index] == null) {
bindings[index] = view;
}
}
}
if (view instanceof ViewGroup) {
final ViewGroup viewGroup = (ViewGroup) view;
final int count = viewGroup.getChildCount();
int minInclude = 0;
for (int i = 0; i < count; i++) {
final View child = viewGroup.getChildAt(i);
boolean isInclude = false;
if (indexInIncludes >= 0 && child.getTag() instanceof String) {
String childTag = (String) child.getTag();
if (childTag.endsWith("_0") &&
childTag.startsWith("layout") && childTag.indexOf('/') > 0) {
// This *could* be an include. Test against the expected includes.
int includeIndex = findIncludeIndex(childTag, minInclude,
includes, indexInIncludes);
if (includeIndex >= 0) {
isInclude = true;
minInclude = includeIndex + 1;
final int index = includes.indexes[indexInIncludes][includeIndex];
final int layoutId = includes.layoutIds[indexInIncludes][includeIndex];
int lastMatchingIndex = findLastMatching(viewGroup, i);
if (lastMatchingIndex == i) {
bindings[index] = DataBindingUtil.bind(bindingComponent, child,
layoutId);
} else {
final int includeCount = lastMatchingIndex - i + 1;
final View[] included = new View[includeCount];
for (int j = 0; j < includeCount; j++) {
included[j] = viewGroup.getChildAt(i + j);
}
bindings[index] = DataBindingUtil.bind(bindingComponent, included,
layoutId);
i += includeCount - 1;
}
}
}
}
if (!isInclude) {
mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
}
}
}
}
}
贴那么多代码,稍微总结下,上面也就是告诉我们所有的控件tag变成了null并都存放到了数组里面(所以你在xml设置tag它是不生效的)。
其次DataBinderMapperImpl.getDataBinder()通过根布局的tag生成ActivityMainBindingImpl,这也是我们最终想要的xml对应databinding的具体实现类
2. 传入的observer如何监听刷新
先看下我们XML设置VM,如何刷新
ActivityMainBindingImpl.java
public void setMainVm(@Nullable com.wqg.wqgdatabdingandviewmodel.MainVm MainVm) {
this.mMainVm = MainVm;
synchronized(this) {
mDirtyFlags |= 0x4L;
}
notifyPropertyChanged(BR.mainVm); // 添加到监听的地方
super.requestRebind(); // 刷新数据
}
protected void requestRebind() {
if (mContainingBinding != null) {
mContainingBinding.requestRebind();
} else {
final LifecycleOwner owner = this.mLifecycleOwner;
if (owner != null) {
Lifecycle.State state = owner.getLifecycle().getCurrentState();
// 判断了必须要在活跃状态才可以刷新数据
if (!state.isAtLeast(Lifecycle.State.STARTED)) {
return; // wait until lifecycle owner is started
}
}
synchronized (this) {
if (mPendingRebind) {
return;
}
mPendingRebind = true;
}
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
}
接着来看下notifyPropertyChanged(BR.mainVm);。从下面代码可以看出来他是要回调刷新,重点看addOnPropertyChangedCallback,反查下发现BaseObservableField构造函数就引用了这个方法。
public class BaseObservable implements Observable {
private transient PropertyChangeRegistry mCallbacks;
public BaseObservable() {
}
// 核心代码,反查下看拿引用
@Override
public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
synchronized (this) {
if (mCallbacks == null) {
mCallbacks = new PropertyChangeRegistry();
}
}
mCallbacks.add(callback);
}
}
abstract class BaseObservableField extends BaseObservable {
public BaseObservableField() {
}
public BaseObservableField(Observable... dependencies) {
if (dependencies != null && dependencies.length != 0) {
DependencyCallback callback = new DependencyCallback();
for (int i = 0; i < dependencies.length; i++) {
// 核心代码,是不是很熟悉,现在是不是有点感觉了为啥val nameF : ObservableField<String>能自动刷新数据呢。接着看
dependencies[i].addOnPropertyChangedCallback(callback);
}
}
}
class DependencyCallback extends Observable.OnPropertyChangedCallback {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
notifyChange();
}
}
}
有点感觉了,为啥val nameF : ObservableField<String>能自动刷新数据更新Ui呢,我们知道livedata内部其实也是observer对象玩的,所以同理。我们就一个点去讲。ActivityMainBindingImpl是继承ViewDataBinding的,创建对象的时候就生成了WeakListListener对象
ViewDataBinding.java
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(
ViewDataBinding viewDataBinding,
int localFieldId,
ReferenceQueue<ViewDataBinding> referenceQueue
) {
return new WeakPropertyListener(viewDataBinding, localFieldId, referenceQueue)
.getListener();
}
};
// 熟悉的味道,它集成了Observable.OnPropertyChangedCallback
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference<Observable> {
final WeakListener<Observable> mListener;
public WeakPropertyListener(
ViewDataBinding binder,
int localFieldId,
ReferenceQueue<ViewDataBinding> referenceQueue
) {
mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);
}
@Override
public WeakListener<Observable> getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@Override
public void removeListener(Observable target) {
target.removeOnPropertyChangedCallback(this);
}
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
}
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
ViewDataBinding binder = mListener.getBinder();
if (binder == null) {
return;
}
Observable obj = mListener.getTarget();
if (obj != sender) {
return; // notification from the wrong object?
}
// 核心代码
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
// ViewDataBinding.java
protected void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver || mInStateFlowRegisterObserver) {
return;
}
// 它来了他来了
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind(); // 是不是又回来了
}
}
通过以上onChanged->handleFieldChange->ActivityMainBindingImpl.onFieldChange和requestRebind();。是不是熟悉的味道
// ActivityMainBindingImpl.java
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0 :
return onChangeMainVmNameF((androidx.databinding.ObservableField<java.lang.String>) object, fieldId);
case 1 :
return onChangeMainVmPwdF((androidx.databinding.ObservableField<java.lang.String>) object, fieldId);
}
return false;
}
private boolean onChangeMainVmNameF(androidx.databinding.ObservableField<java.lang.String> MainVmNameF, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x1L;
}
return true;
}
return false;
}
protected void requestRebind() {
if (mContainingBinding != null) {
mContainingBinding.requestRebind();
} else {
final LifecycleOwner owner = this.mLifecycleOwner;
if (owner != null) {
Lifecycle.State state = owner.getLifecycle().getCurrentState();
if (!state.isAtLeast(Lifecycle.State.STARTED)) {
return; // wait until lifecycle owner is started
}
}
synchronized (this) {
if (mPendingRebind) {
return;
}
mPendingRebind = true;
}
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
// 看到这个ui了吗?
mUIThreadHandler.post(mRebindRunnable);
}
}
}
是不是看到我们的ui线程了,其实不用说也知道是要更新ui了,再废话一波。
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
processReferenceQueue();
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();
}
};
ViewDataBinding.java
public void executePendingBindings() {
if (mContainingBinding == null) {
executeBindingsInternal();
} else {
mContainingBinding.executePendingBindings();
}
}
private void executeBindingsInternal() {
if (mIsExecutingPendingBindings) {
requestRebind();
return;
}
if (!hasPendingBindings()) {
return;
}
mIsExecutingPendingBindings = true;
mRebindHalted = false;
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBIND, null);
if (mRebindHalted) {
mRebindCallbacks.notifyCallbacks(this, HALTED, null);
}
}
if (!mRebindHalted) {
executeBindings(); //它又来了
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
}
}
mIsExecutingPendingBindings = false;
}
最后他又回到了ActivityMainBindingImpl. executeBindings();激动的心颤抖的手,
ActivityMainBindingImpl.java
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
com.wqg.wqgdatabdingandviewmodel.MainVm mainVm = mMainVm;
java.lang.String mainVmNameFGet = null;
androidx.databinding.ObservableField<java.lang.String> mainVmNameF = null;
java.lang.String mainVmPwd = null;
androidx.databinding.ObservableField<java.lang.String> mainVmPwdF = null;
java.lang.String mainVmName = null;
java.lang.String mainVmPwdFGet = null;
if ((dirtyFlags & 0xfL) != 0) {
if ((dirtyFlags & 0xdL) != 0) {
if (mainVm != null) {
// read mainVm.nameF
mainVmNameF = mainVm.getNameF();
}
updateRegistration(0, mainVmNameF); // 这个就是observerField更新刷新ui
if (mainVmNameF != null) {
// read mainVm.nameF.get()
mainVmNameFGet = mainVmNameF.get();
}
}
if ((dirtyFlags & 0xcL) != 0) {
if (mainVm != null) {
// read mainVm.pwd
mainVmPwd = mainVm.getPwd();
// read mainVm.name
mainVmName = mainVm.getName();
}
}
if ((dirtyFlags & 0xeL) != 0) {
if (mainVm != null) {
// read mainVm.pwdF
mainVmPwdF = mainVm.getPwdF();
}
updateRegistration(1, mainVmPwdF);
if (mainVmPwdF != null) {
// read mainVm.pwdF.get()
mainVmPwdFGet = mainVmPwdF.get();
}
}
}
// batch finished
if ((dirtyFlags & 0xcL) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.et1, mainVmName);
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv1, mainVmName);
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv2, mainVmPwd);
}
if ((dirtyFlags & 0x8L) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et1androidTextAttrChanged);
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et2, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et2androidTextAttrChanged);
}
if ((dirtyFlags & 0xdL) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.et2, mainVmNameFGet);
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv3, mainVmNameFGet);
}
if ((dirtyFlags & 0xeL) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv4, mainVmPwdFGet);
}
}
上面我们看到了它会从vm的各个对象取值并更新给ui数据。其中updateRegistration(0, mainVmNameF); 是observerField对象更新数据了通知刷新ui,最后也是回到了requestRebind,下面说下
// ViewDataBinding.java
protected boolean updateRegistration(int localFieldId, Observable observable) {
// CREATE_PROPERTY_LISTENER 是不是又回到之前说的了
return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}
之前说过CREATE_PROPERTY_LISTENER对象,你可以把他当做它就是一个观察者,相当把observable封装到了CREATE_PROPERTY_LISTENER内部的WeakPropertyListener对应的target里面。甚至你可以理解他们是等价的,专门对属性进行监听,那是不是又回到之前WeakPropertyListener的讲解了。当属性发生变化的时候触发WeakPropertyListener.onPropertyChanged,之后就是前面说的代码了。
// 熟悉的味道,它集成了Observable.OnPropertyChangedCallback
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference<Observable> {
final WeakListener<Observable> mListener;
public WeakPropertyListener(
ViewDataBinding binder,
int localFieldId,
ReferenceQueue<ViewDataBinding> referenceQueue
) {
mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);
}
@Override
public WeakListener<Observable> getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@Override
public void removeListener(Observable target) {
target.removeOnPropertyChangedCallback(this);
}
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
}
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
ViewDataBinding binder = mListener.getBinder();
if (binder == null) {
return;
}
Observable obj = mListener.getTarget();
if (obj != sender) {
return; // notification from the wrong object?
}
// 核心代码
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
双向绑定咋实现的
还是看刚刚上面代码,是不是又很熟悉了,它自己帮你添加监听回调了。这个比较简单就不过多介绍了,原理其实和上面差不多了
//监听
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et1androidTextAttrChanged);
private androidx.databinding.InverseBindingListener et1androidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
@Override
public void onChange() {
java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(et1);
// localize variables for thread safety
// mainVm
com.wqg.wqgdatabdingandviewmodel.MainVm mainVm = mMainVm;
// mainVm.name
java.lang.String mainVmName = null;
// mainVm != null
boolean mainVmJavaLangObjectNull = false;
mainVmJavaLangObjectNull = (mainVm) != (null);
if (mainVmJavaLangObjectNull) {
mainVm.setName(((java.lang.String) (callbackArg_0)));
}
}
};