https://developer.android.com/topic/libraries/data-binding
https://blog.csdn.net/qiang_xi/article/details/74347880
DataBindingUtil
ActivityMain2Binding生成的绑定类
以上静态方法都可以获取绑定对象,但有什么区别呢,这就需要去看看源码怎么实现的了。
当我们在xml中写完布局绑定后,编译后会自动生成几个java和处理过的布局xml,具体路径为build里的:
其中对布局根view设置的tag是layout/xml名字_0,例如布局是databinding1.xml,那么android:tag="layout/databinding1_0"。
当然如果你放的布局xml在其他layout文件夹(比如layout-land)那么前边的layout就是那个文件夹名。
布局根view设置的tag是为了在后边获取绑定对象的。
这个是个方便的方法,setContentView后同时获取绑定对象。
public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity, int layoutId, @Nullable DataBindingComponent bindingComponent) { 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 root, int layoutId) { return (T) sMapper.getDataBinder(bindingComponent, root, layoutId); }
com.example.jetpackdemo.DataBinderMapperImpl
private static final int LAYOUT_ACTIVITYMAIN2 = 1; private static final int LAYOUT_ACTIVITYMAIN3 = 2; private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(2); static { INTERNAL_LAYOUT_ID_LOOKUP.put(com.example.jetpackdemo.R.layout.activity_main2, LAYOUT_ACTIVITYMAIN2); INTERNAL_LAYOUT_ID_LOOKUP.put(com.example.jetpackdemo.R.layout.activity_main3, LAYOUT_ACTIVITYMAIN3); } @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_ACTIVITYMAIN2: { if ("layout/activity_main2_0".equals(tag)) { return new ActivityMain2BindingImpl(component, view); } throw new IllegalArgumentException("The tag for activity_main2 is invalid. Received: " + tag); } case LAYOUT_ACTIVITYMAIN3: { if ("layout/activity_main3_0".equals(tag)) { return new ActivityMain3BindingImpl(component, view); } throw new IllegalArgumentException("The tag for activity_main3 is invalid. Received: " + tag); } } } return null; }
可以看出,最终是通过获取view的tag(这个tag就是前边说的处理后的 xml自动加上的tag),根据tag来创建具体的绑定对象的。
private ActivityMain2BindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) { super(bindingComponent, root, 0 , (android.widget.LinearLayout) bindings[0] , (android.widget.TextView) bindings[3] , (android.widget.TextView) bindings[2] , (android.widget.TextView) bindings[4] ); this.mboundView0 = (com.example.jetpackdemo.databinding.ActivityMain3Binding) bindings[6]; setContainedBinding(this.mboundView0); this.mboundView1 = (android.widget.TextView) bindings[1]; this.mboundView1.setTag(null); this.mboundView5 = (android.widget.TextView) bindings[5]; this.mboundView5.setTag(null); this.root.setTag(null); this.tvAge.setTag(null); this.tvName.setTag(null); this.tvSex.setTag(null); setRootTag(root); // listeners mCallback1 = new com.example.jetpackdemo.generated.callback.OnClickListener(this, 1); invalidateAll(); }
protected void setRootTag(View view) { view.setTag(R.id.dataBinding, this); }
可以看到创建后,就把root的tag设置为null,并设置了view.setTag(R.id.dataBinding, this),就是做了个缓存,以后从此view就可以直接获取绑定对象。
public static <T extends ViewDataBinding> T bind(@NonNull View root, DataBindingComponent bindingComponent) { T binding = getBinding(root); if (binding != null) { return binding; } Object tagObj = root.getTag(); if (!(tagObj instanceof String)) { throw new IllegalArgumentException("View is not a binding layout"); } else { String tag = (String) tagObj; int layoutId = sMapper.getLayoutId(tag); if (layoutId == 0) { throw new IllegalArgumentException("View is not a binding layout. Tag: " + tagObj); } return (T) sMapper.getDataBinder(bindingComponent, root, layoutId); } }
DataBindingUtil.getBinding最终会调用ViewDataBinding的getBinding
static ViewDataBinding getBinding(View v) { if (v != null) { return (ViewDataBinding) v.getTag(R.id.dataBinding); } return null; }
如果没有找到缓存,sMapper.getLayoutId(tag)
com.example.jetpackdemo.DataBinderMapperImpl
@Override public int getLayoutId(String tag) { if (tag == null) { return 0; } Integer tmpVal = InnerLayoutIdLookup.sKeys.get(tag); return tmpVal == null ? 0 : tmpVal; } private static class InnerLayoutIdLookup { static final HashMap<String, Integer> sKeys = new HashMap<String, Integer>(2); static { sKeys.put("layout/databinding1_0", com.example.jetpackdemo.R.layout.databinding1); sKeys.put("layout/databinding2_0", com.example.jetpackdemo.R.layout.databinding2); } }
从上边可以看出:
public static <T extends ViewDataBinding> T inflate( @NonNull LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent, boolean attachToParent, @Nullable DataBindingComponent bindingComponent) { final boolean useChildren = parent != null && attachToParent; final int startChildren = useChildren ? parent.getChildCount() : 0; final View view = inflater.inflate(layoutId, parent, attachToParent); if (useChildren) { return bindToAddedViews(bindingComponent, parent, startChildren, layoutId); } else { return bind(bindingComponent, view, layoutId); } }
可以看到这种方式,是在xml还没有解析过时才用的,一般用在fragment,list view的adapter等里。
public static <T extends ViewDataBinding> T getBinding(@NonNull View view) { return (T) ViewDataBinding.getBinding(view); }
static ViewDataBinding getBinding(View v) { if (v != null) { return (ViewDataBinding) v.getTag(R.id.dataBinding); } return null; }
也就是找缓存,找不到就返回null。
检索负责给定View的绑定。 如果view不是绑定布局的根,则将在其父级中搜索绑定。 如果没有绑定,则将返回null。
也就是说会向上搜索。
public static <T extends ViewDataBinding> T findBinding(@NonNull View view) { while (view != null) { ViewDataBinding binding = ViewDataBinding.getBinding(view); if (binding != null) { return (T) binding; } Object tag = view.getTag(); if (tag instanceof String) { String tagString = (String) tag; if (tagString.startsWith("layout") && tagString.endsWith("_0")) { final char nextChar = tagString.charAt(6); final int slashIndex = tagString.indexOf(‘/‘, 7); boolean isUnboundRoot = false; if (nextChar == ‘/‘) { // only one slash should exist isUnboundRoot = slashIndex == -1; } else if (nextChar == ‘-‘ && slashIndex != -1) { int nextSlashIndex = tagString.indexOf(‘/‘, slashIndex + 1); // only one slash should exist isUnboundRoot = nextSlashIndex == -1; } if (isUnboundRoot) { // An inflated, but unbound layout return null; } } } ViewParent viewParent = view.getParent(); if (viewParent instanceof View) { view = (View) viewParent; } else { view = null; } } return null; }
public static ActivityMain2Binding inflate(@NonNull LayoutInflater inflater) { return inflate(inflater, DataBindingUtil.getDefaultComponent()); }
public static ActivityMain2Binding inflate(@NonNull LayoutInflater inflater, @Nullable Object component) { return ViewDataBinding.<ActivityMain2Binding>inflateInternal(inflater, R.layout.activity_main2, null, false, component); }
可以看出其实每个生成的绑定类,都是知道自己是和哪个布局进行绑定的。
ViewDataBinding
protected static <T extends ViewDataBinding> T inflateInternal( @NonNull LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent, boolean attachToParent, @Nullable Object bindingComponent) { return DataBindingUtil.inflate( inflater, layoutId, parent, attachToParent, checkAndCastToBindingComponent(bindingComponent) ); }
接着就会走DataBindingUtil.inflate()
public static ActivityMain2Binding bind(@NonNull View view) { return bind(view, DataBindingUtil.getDefaultComponent()); }
public static ActivityMain2Binding bind(@NonNull View view, @Nullable Object component) { return (ActivityMain2Binding)bind(component, view, R.layout.activity_main2); }
ViewDataBinding
protected static ViewDataBinding bind(Object bindingComponent, View view, int layoutId) { return DataBindingUtil.bind( checkAndCastToBindingComponent(bindingComponent), view, layoutId); }
2.2.2.Architecture components_data binding2_源码分析
原文:https://www.cnblogs.com/muouren/p/12368516.html