Please indicate the source of Reprint: http://blog.csdn.net/zhaoyanjun6/article/details/120751996
This article comes from [Zhao Yanjun's blog]
What is View Binding
View Binding is a new feature introduced by Android Studio 3.6 to replace findviewbyid (internal implementation or use findViewById).. After starting View Binding, the system will generate a binding class for each xml file in the module. The instance of the binding class contains direct references to all views with ID S in the corresponding layout.
Advantages of View Binding
- Null security: since view binding creates a direct reference to the view, there is no risk of null pointer exception due to invalid view ID. In addition, if the view appears only in some configurations of the layout, the fields in the binding class that contain its references are marked with @ Nullable.
- Type safe: fields in each binding class have types that match the views they reference in the XML file. This means that there is no risk of class conversion exceptions.
How to enable View Binding
android { buildFeatures { viewBinding true } }
If you want to ignore a layout file when generating binding classes, add the tools:viewBindingIgnore="true" attribute to the root view of the corresponding layout file:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:viewBindingIgnore="true" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
How to use View Binding
After using the view Binding function, the system will generate a Binding class for each XML layout file contained in the module. The class name of this class is named after the XML layout file name, with the word capitalized and Binding removed. Such as activity_ Class ActivityMainBinding.xml generated by main.xml
Activity binding view
-
Step 1: call the static inflate() method contained in the generated binding class. This creates an instance of the binding class for use by the Activity.
-
Step 2: get the reference to the root view by calling the getRoot() method or using the Kotlin attribute syntax.
-
Step 3: pass the root view to setContentView() to make it the active view on the screen.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tv" android:layout_width="100dp" android:layout_height="100dp" android:background="#77f" android:text="Zhao Yanjun" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
use:
class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //critical code binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) //Get control binding.tv.setOnClickListener { Toast.makeText(this, "hahha", Toast.LENGTH_SHORT).show() } } }
Fragment binding view
How to use view binding in a Fragment? Please perform the following steps in the onCreateView() method of the Fragment (Note: the Fragment exists longer than its view. Be sure to clear all references to bound class instances in the onDestroyView() method of the Fragment.)
-
Call the static inflate() method contained in the generated binding class. This creates an instance of the binding class for Fragment use.
-
Get a reference to the root view by calling the getRoot() method or using the Kotlin attribute syntax.
-
Returns the root view from the onCreateView() method, making it the active view on the screen
//fragment_my.xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="40dp" android:text="This is Fragment Button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="40dp" android:gravity="center" android:text="This is FragmentTextView" app:layout_constraintBottom_toTopOf="@+id/button" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
public class MyFragment extends Fragment { private FragmentMyBinding binding; public MyFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentMyBinding.inflate(inflater, container, false); return binding.getRoot(); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); binding.textView.setText("This is Fragment"); binding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("Fragment", "Click the button"); } }); } @Override public void onDestroy() { super.onDestroy(); binding = null; }
Using View Binding in onViewCreated
//Using View Binding in onViewCreated public class MyFragment extends Fragment { private FragmentMyBinding binding; public MyFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_my,container,false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentMyBinding binding = FragmentMyBinding.bind(view); this.binding = binding; binding.textView.setText("This is Fragment"); binding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("Fragment", "Click the button"); } }); } @Override public void onDestroy() { super.onDestroy(); binding = null; }
Base class written using View Binding
1. Through reflection (this method is not recommended and may cause confusion)
Activity base class design
//Java public class BaseActivity<T extends ViewBinding> extends AppCompatActivity { protected T viewBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); Class cls = (Class) type.getActualTypeArguments()[0]; try { Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class); viewBinding = (T) inflate.invoke(null, getLayoutInflater()); setContentView(viewBinding.getRoot()); } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) { e.printStackTrace(); } } } //use public class MainActivity extends BaseActivity<ActivityMainBinding> { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewBinding.button.setText("This is MainActivity ViewBinding"); viewBinding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("MainView","Click the button"); } }); } }
//Kotlin open class BaseActivity<T : ViewBinding> : AppCompatActivity() { protected lateinit var binding: T override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val type = javaClass.genericSuperclass as ParameterizedType val aClass = type.actualTypeArguments[0] as Class<*> val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) binding = method.invoke(null, layoutInflater) as T setContentView(binding.root) } } class MainActivity : BaseActivity<ActivityMainBinding>() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding.textView.text = "This is MainActivity" } }
Fragment base class design
//Java public class BaseFragment<T extends ViewBinding> extends Fragment { protected T viewBinding; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); Class cls = (Class) type.getActualTypeArguments()[0]; try { Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class); viewBinding = (T) inflate.invoke(null, inflater, container, false); } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) { e.printStackTrace(); } return viewBinding.getRoot(); } } //use public class MainFragment extends BaseFragment<FragmentMainBinding>{ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewBinding.button.setText("This is MainFragment ViewBinding"); viewBinding.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("MainView","Click the button"); } }); } }
//Kotlin open class BaseFragment<T:ViewBinding>:Fragment(){ lateinit var binding: T override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val type = javaClass.genericSuperclass as ParameterizedType val aClass = type.actualTypeArguments[0] as Class<*> val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java) binding = method.invoke(null,layoutInflater,container,false) as T return binding.root } } class FirstFragment : BaseFragment<FragmentFirstBinding>() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.textView.text = "This is FirstFragment" } }
2. Not through reflection
Activity base class design
abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() { private lateinit var _binding: T protected val binding get() = _binding; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) _binding = getViewBinding() setContentView(_binding.root) } protected abstract fun getViewBinding(): T } class MainActivity : BaseActivity<ActivityMainBinding>() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding.textView.text = "This is MainActivity" } override fun getViewBinding() = ActivityMainBinding.inflate(layoutInflater) }
Fragment base class design
abstract class BaseFragment<T : ViewBinding> : Fragment() { private lateinit var _binding: T protected val binding get() = _binding; override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = getViewBinding(inflater, container) return _binding.root } protected abstract fun getViewBinding(inflater: LayoutInflater, container: ViewGroup?): T } class FirstFragment : BaseFragment<FragmentFirstBinding>() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.textView.text = "This is FirstFragment" } override fun getViewBinding( inflater: LayoutInflater, container: ViewGroup? ) = FragmentFirstBinding.inflate(inflater, container, false) }