以activity举例,我们的MainActivity的结构是activity_main,之前我们结构代码是:
class MainActivity : BaseActivity() { private lateinit var button: Button private lateinit var viewPager: ViewPager2 private lateinit var recyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button = findViewById(R.id.button) button.setOnClickListener { ... } }}如今就要改为
对应的Binding类如ActivityMainBinding类去用inflate加载结构
然后通过getRoot获取到View
将View传入到setContentView(view:View)中
Activity就能表现activity_main.xml这个结构的内容了,并可以通过Binding对象直接访问对应View对象。
class MainActivity : BaseActivity() { private lateinit var mBinding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(mBinding.root) mBinding.button.setOnClickListener { ... } }}而在其他UI elements中,如fragment、dialog、adapter中,利用方式大同小异,都是通过inflate去加载出View,然后反面加以利用。
四、原理
天生的类可以在/build/generated/data_binding_base_class_source_out下找到
public final class ActivityMainBinding implements ViewBinding { @NonNull private final ConstraintLayout rootView; @NonNull public final Button button; @NonNull public final RecyclerView recyclerView; @NonNull public final ViewPager2 viewPager; private ActivityMainBinding(@NonNull ConstraintLayout rootView, @NonNull Button button, @NonNull RecyclerView recyclerView, @NonNull ViewPager2 viewPager) { this.rootView = rootView; this.button = button; this.recyclerView = recyclerView; this.viewPager = viewPager; } @Override @NonNull public ConstraintLayout getRoot() { return rootView; } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) { return inflate(inflater, null, false); } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, boolean attachToParent) { View root = inflater.inflate(R.layout.activity_main, parent, false); if (attachToParent) { parent.addView(root); } return bind(root); } @NonNull public static ActivityMainBinding bind(@NonNull View rootView) { // The body of this method is generated in a way you would not otherwise write. // This is done to optimize the compiled bytecode for size and performance. int id; missingId: { id = R.id.button; Button button = ViewBindings.findChildViewById(rootView, id); if (button == null) { break missingId; } id = R.id.recycler_view; RecyclerView recyclerView = ViewBindings.findChildViewById(rootView, id); if (recyclerView == null) { break missingId; } id = R.id.view_pager; ViewPager2 viewPager = ViewBindings.findChildViewById(rootView, id); if (viewPager == null) { break missingId; } return new ActivityMainBinding((ConstraintLayout) rootView, button, recyclerView, viewPager); } String missingId = rootView.getResources().getResourceName(id); throw new NullPointerException("Missing required view with ID: ".concat(missingId)); }}可以看到关键的方法就是这个bind方法,内里通过ViewBindings.findChildViewById获取View对象,而继续查察这个方法
public class ViewBindings { private ViewBindings() { } /** * Like `findViewById` but skips the view itself. * * @hide */ @Nullable public static <T extends View> T findChildViewById(View rootView, @IdRes int id) { if (!(rootView instanceof ViewGroup)) { return null; } final ViewGroup rootViewGroup = (ViewGroup) rootView; final int childCount = rootViewGroup.getChildCount(); for (int i = 0; i < childCount; i++) { final T view = rootViewGroup.getChildAt(i).findViewById(id); if (view != null) { return view; } } return null; }}可见照旧利用的findViewById,ViewBinding这个框架只是帮我们在编译阶段自动天生了这些findViewById代码,省去我们去写了。
五、优缺点