Jetpack series (8) – Data Binding && View Binding
A brief introduction to Hilt
First impression
Data Binding, including all View Binding functions, support bidirectional Binding
View Binding only supports Binding views, an alternative to the Kotlin-Android-Extensions plugin
Data Binding and View Binding can exist together
Data Binding performance is inferior to View Binding, so some projects only use View Binding
The basic concept
I’m just going to use a View Binding instead of findViewById(), Data Binding
The basic use
View Binding basic use
- will
viewBinding
Element to whichbuild.gradle
In the file
android {
...
viewBinding {
enabled = true}}Copy the code
-
Use view bindings in your Activity
- In the Activity
onCreate()
Method to call the static contained in the generated binding classinflate()
methods - with
Binding. The control Id
Operating controls
// MainActivity class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?). { super.onCreate(savedInstanceState) // Automatically generated binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) } } Copy the code
- In the Activity
-
Use view binding in fragments
- Please in fragments
onCreateView()
Method, calling the static contained in the generated binding classinflate()
methods
class DeepLinkFragment : Fragment() { private var _binding: FragmentDeepLinkBinding? = null private val binding get() = _binding!! private val mainViewModel: MainViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState:Bundle?).: View { _binding = FragmentDeepLinkBinding.inflate(inflater, container, false) return binding.root } override fun onDestroy(a) { super.onDestroy() _binding = null}}Copy the code
- Please in fragments
-
Use ViewBinding in Adapter
- By binding classes
inflate
Methods the incomingViewHolder
// WordListAdapter.kt class WordListAdapter : ListAdapter<Word, WordViewHolder>(WORDS_COMPARATOR) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder = WordViewHolder.create(parent) override fun onBindViewHolder(holder: WordViewHolder, position: Int) { val item = getItem(position) holder.bind(item) } companion object { private val WORDS_COMPARATOR = object : DiffUtil.ItemCallback<Word>() { override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean = oldItem == newItem override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean = oldItem.word == newItem.word } } } class WordViewHolder(binding: ItemWordBinding) : RecyclerView.ViewHolder(binding.root) { private val textView: TextView = binding.textView fun bind(word: Word?).{ textView.text = word? .word? :"" } companion object { fun create(parent: ViewGroup): WordViewHolder { val binding = ItemWordBinding.inflate(LayoutInflater.from(parent.context), parent, false) return WordViewHolder(binding) } } } Copy the code
- By binding classes
Data Binding basic use
-
Modify the build.gradle file
dataBinding { enabled = true } Copy the code
-
Generate the data Binding layout, see Point 3
- I’m going to do a refresh effect here
- Click on the event
onClick="@{()-> model.updateTaps()}"
<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"> <data> <variable name="model" type="com.huang.myapplication.viewmodel.MainViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/home_contain" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.main.home.HomeFragment"> <Button android:id="@+id/btn_add" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="10dp" android:layout_marginTop="10dp" android:layout_marginEnd="10dp" android:text="@string/refresh" android:onClick="@{()-> model.updateTaps()}" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toRightOf="@+id/btn_next" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:text="@{model.taps}" app:layout_constraintBottom_toBottomOf="@+id/tv_current_count" app:layout_constraintLeft_toRightOf="@+id/tv_current_count" app:layout_constraintTop_toTopOf="@+id/tv_current_count" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout> Copy the code
-
Look at the data in the viewModel
class MainViewModel @Inject constructor( private val repository: WordRepository ) : ViewModel() { private var _tapCount = 0 private var _taps = MutableLiveData<String>("$_tapCount taps") val taps: LiveData<String> = _taps fun updateTaps(a) { _tapCount++ _taps.value = "$_tapCount taps"}}Copy the code
-
Binding view
-
The Activity generates the Binding view class
// Method 1: val binding: ActivityXxxBinding = DataBindingUtil.setContentView( this, R.layout.activity_main) // Method 2: val binding: ActivityXxxBinding = ActivityMainBinding.inflate(getLayoutInflater()) Copy the code
-
Use data binding items in Fragment, ListView, or RecyclerView adapters
// Method 1: val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // Method 2: val listItemBinding = DataBindingUtil.inflate(layoutInflater,R.layout.list_item, viewGroup, false) Copy the code
-
You can use LiveData objects as data binding sources to automatically notify the interface of data changes, requiring binding.lifecycleOwner = this to set the lifecycle of the view-binding class
class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! private lateinit var adapter: WordListAdapter private val mainViewModel: MainViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState:Bundle?).: View { _binding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_home,container, false) setHasOptionsMenu(true) binding.lifecycleOwner = this return binding.root } override fun onDestroy(a) { super.onDestroy() _binding = null}}Copy the code
-
Related knowledge points
ViewBinding ignores files
-
Once ViewBinding is enabled, Android Studio automatically generates a Binding class for each layout file we write
-
The Binding class is named after the layout file is humped and ends with a Binding.
-
If there are layout files for which you do not want to generate a Binding class, you can add tools at the root of the layout file :viewBindingIgnore=”true”
<LinearLayout . tools:viewBindingIgnore="true" >.</LinearLayout> Copy the code
Include layout in a View Binding
-
The View Binding uses an include to add an ID, which is searched by id
<include android:id="@+id/includeTitle" layout="@layout/include_title" />/ / InOutFragment kt binding. IncludeTitle. ToolbarTitle. Text = "in operation"Copy the code
Quickly generate a Data Binding layout
alt + Enter
choosecover data to data binding layout
Binding expressions (Data Bindng)
- Arithmetic operator
+ - / * %
- String concatenation operator
+
- Logical operator
&& | |
- Binary operator
& | ^
- Unary operator
+ -! ~
- Shift operator
>> >>> <<
- Comparison operator
== > < >= <=
(Please note that<
Need to escape as<
) instanceof
- Grouping operator
(a)
- Literal operators – characters, strings, numbers,
null
- Type conversion
- The method call
- Field access
- Array access
[]
- Ternary operator
? :
Data Binding
@ = {}
The notation, which importantly contains the “=” symbol, receives data changes for attributes and listens for user updates at the same time
A link to the
Jetpack (1) – Navigation
Jetpack series (Ii) — Lifecycle
Jetpack series (3) – LiveData
Jetpack series (4) – ViewModel
Jetpack series (5) — Room
Jetpack series (6) – Paging3
Jetpack (7) – Hilt
The resources
A website
Website 2