Clean up findViewById from source code with DataBindingLibrary

Overview

One of the components of * Android Jetpack *, [* Data Binding Library *](https://developer. A memorandum that uses android.com/topic/libraries/data-binding/?hl=JA) to wipe out the acquisition of View by findViewById from within the source code.

1. Enable * Data Binding Library * from build.gradle

app/build.gradle


android { 
    //Omission
    dataBinding {
        enabled = true
    }
}

Add the above

2. Enclose the layout settings in the layout / *. xml file in<layout> </ layout>

layout/*.xml


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <!--Layout settings-->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".HogeActivity">

        <!--Omission-->

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

Add <layout> </ layout> to the head and butt and move only xmlns: to <layout>. Then, the * Binding class that inherits ViewDataBinding is automatically generated based on layout / *. Xml. The class name is the xml name converted to UpperCamelCase. If it is not automatically generated, it may come out if you rebuild it once.

4. Use the Binding class

The method differs slightly depending on the target to be specified.

For Activity

Activity.java


 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity);
+    final ActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.activity);

-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    binding.textView.setText("HogeFuga");

Note the return type of DataBindingUtil.setContentView. (Because it is a generic type, any class that inherits ViewDataBinding will be accepted)

For Fragment (Pattern 1)

Fragment.java


+private FragmentBinding binding;

 @Override
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                          @Nullable Bundle savedInstanceState) {
-    return inflater.inflate(R.layout.fragment, container, false);
+    binding = FragmentBinding.inflate(inflater, container, false);
+    return binding.getRoot();
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
     super.onActivityCreated(savedInstanceState);
-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    binding.textView.setText("HogeFuga");
 }

A pattern that creates a View from the Binding class. Is it not good to have a Binding class in the field?

For Fragment (Pattern 2)

Fragment.java


+private FragmentBinding binding;

 @Override
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                          @Nullable Bundle savedInstanceState) {
     return inflater.inflate(R.layout.fragment, container, false);
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
     super.onActivityCreated(savedInstanceState);
-    final TextView textView = findViewById(R.is.text_view);
-    textView.setText("HogeFuga");
+    final FragmentBinding binding = FragmentBinding.bind(getView());
+    binding.textView.setText("HogeFuga");
 }

A pattern that creates a View first and then creates a Binding instance based on it. In this case it is not necessary to have it in the field.

For RecyclerView.Adapter

diff:RecyclerView.Adapter.java


 @NonNull
 @Override
 public MainViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-    final View view = inflater.inflate(R.layout.recycler_row, parent, false);
-    return new ViewHolder(view);
+    final RecyclerViewAdapterBinding binding = RecyclerViewAdapterBinding.inflate(inflater, parent, false);
+    return new ViewHolder(binding);
 }

 @Override
 public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
     holder.bind("HogeFuga");
 }

 class ViewHolder extends RecyclerView.ViewHolder {
     @NonNull
-    private final TextView textView;
+    private final RecyclerRowBinding binding;

-    private MainViewHolder(@NonNull View view) {
-        super(view);
-        textView = view.findViewById(R.id.text_view);
+    private MainViewHolder(@NonNull RecyclerRowBinding binding) {
+        super(binding.getRoot());
+        this.binding = binding;
     }

     void bind(@NonNull String text) {
-        textView.setText(text);
+        binding.textView.setText(text);
     }
 }

If you use it for * RecyclerView.Adapter *, I think it's better to use * groupie * or * epoxy * so that * RecyclerView.ViewHolder * is no longer needed.

Points to be worried about

--Which of patterns 1 and 2 is more appropriate when used for Fragment?

Recommended Posts

Clean up findViewById from source code with DataBindingLibrary
Clean your code with Butter Knife
Code Java from Emacs with Eclim
Install samba4 from source code on CentOS8
[Java] Flow from source code to execution
Generate source code from JAR file with JD-GUI of Java Decompiler project
Execute Java code from cpp with cocos2dx
A memorandum to clean up the code Ruby