DataBinding Ringan untuk Android

Halo para pembaca yang budiman. Kita semua menyukai dan menggunakan DataBinding , yang diperkenalkan Google beberapa tahun lalu, untuk menautkan model data ke tampilan melalui ViewModel. Pada artikel ini, saya ingin berbagi dengan Anda bagaimana Anda dapat menyatukan proses ini menggunakan bahasa Kotlin, dan menyesuaikan pembuatan adaptor untuk RecyclerView (selanjutnya disebut RV), ViewPager dan ViewPager2 dalam beberapa baris kode.





Untuk memulainya, kami biasa mengembangkan adaptor khusus yang dibuat oleh ViewHolders di balik terpal, dan tulisan mereka, dan bahkan lebih banyak dukungan, membutuhkan cukup banyak waktu. Di bawah ini adalah contoh adaptor RV biasa:





class CustomAdapter(private val dataSet: Array<String>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {    
    
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView        
        init {
            textView = view.findViewById(R.id.textView)
        }
    }   
    
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.text_row_item, viewGroup, false)        
      return ViewHolder(view)
    }    
     
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {        // Get element from your dataset at this position and replace the
        viewHolder.textView.text = dataSet[position]
    }    
    
    override fun getItemCount() = dataSet.size
}
      
      



Saat proyek berkembang, mungkin ada lebih banyak adaptor ini. Saya ingat suatu kali, adaptor itu sangat besar, beberapa ratus baris kode, sehingga butuh waktu yang sangat lama untuk mencari tahu apa yang terjadi di sana, dan bahkan lebih untuk menambahkan sesuatu yang baru, karena ini bekerja dengan model data yang berbeda, dan juga harus membuat pemetaan yang berbeda untuk setiap tipe data. Sejujurnya, itu sulit.





DataBinding , , onCreateViewHolder



, LayoutInflater



, DataBindingUtil.inflate



, .





class BindingViewHolder(val binding: ItemTextRowBinding) : RecyclerView.ViewHolder(binding.root)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
        val binding = DataBindingUtil.inflate<ItemTextRowBinding>(LayoutInflater.from(parent.context), viewType, parent, false)
        val viewHolder = BindingViewHolder(binding)
        return viewHolder
}

override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {    
  holder.binding.setVariable(BR.item, dataSet[position])
}
      
      



, RV, , . BindingAdapter androidx.databinding. , , RV, - DataBindingRecyclerViewConfig



, .





, EasyRecyclerBinding. BindingAdapters ViewPager ViewPager2. :

1) , , , RV, - app:items



app:rv_config



.





<?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">

    <data>
    	<variable
        	name="vm"
        	type="com.rasalexman.erb.ui.base.ExampleViewModel" />

        <variable
            name="rvConfig"
            type="com.rasalexman.easyrecyclerbinding.DataBindingRecyclerViewConfig" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:items="@{vm.items}"
            app:rv_config="@{rvConfig}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:listitem="@layout/item_recycler"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
      
      



ViewModel, , , RV, DataBindingRecyclerViewConfig.





//       
class ExampleViewModel : ViewModel() {  
   val items: MutableLiveData<MutableList<RecyclerItemUI>> = MutableLiveData()
}

data class RecyclerItemUI(
    val id: String,
    val title: String
)
      
      



, , .





<?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">

    <data>

        <variable
            name="item"
            type="com.rasalexman.erb.models.RecyclerItemUI" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:drawable/list_selector_background">

        <TextView
            android:id="@+id/titleTV"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="16dp"
            android:paddingTop="8dp"
            android:paddingEnd="16dp"
            android:textColor="@color/black"
            android:textSize="18sp"
            android:text="@{item.title}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="Hello world" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="16dp"
            android:paddingEnd="16dp"
            android:paddingBottom="8dp"
            android:textColor="@color/gray"
            android:textSize="14sp"
            android:text="@{item.id}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/titleTV"
            tools:text="Hello world" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
      
      



2) dataBinding, - createRecyclerConfig<I : Any, BT : ViewDataBinding>



, DataBindingRecyclerViewConfig, id , , .





class RecyclerViewExampleFragment : BaseBindingFragment<RvExampleFragmentBinding, ExampleViewModel>() {    
  override val layoutId: Int get() = R.layout.rv_example_fragment
  override val viewModel: ExampleViewModel by viewModels()    
  
  override fun initBinding(binding: RvExampleFragmentBinding) {
        super.initBinding(binding)
        binding.rvConfig = createRecyclerConfig<RecyclerItemUI, ItemRecyclerBinding> {
            layoutId = R.layout.item_recycler
        		itemId = BR.item            
        }
    }
}
      
      



, , ViewModel RV. , onItemClick, onItemCreate, onItemBind



  .





, , EasyRecyclerBinding - IBindingModel



  layoutResId



, - id , .





data class RecyclerItemUI(    
		val id: String,
    val title: String
) : IBindingModel {    
    override val layoutResId: Int        
    		get() = R.layout.item_recycler
}
data class RecyclerItemUI2(
    val id: String,
    val title: String
) : IBindingModel {
    override val layoutResId: Int
        get() = R.layout.item_recycler2
}
      
      



, , - createRecyclerMultiConfig



, .





class RecyclerViewExampleFragment : BaseBindingFragment<RvExampleFragmentBinding, RecyclerViewExampleViewModel>() {    
  override val layoutId: Int get() = R.layout.rv_example_fragment
    override val viewModel: RecyclerViewExampleViewModel by viewModels()
    
    override fun initBinding(binding: RvExampleFragmentBinding) {
        super.initBinding(binding)
        binding.rvConfig = createRecyclerMultiConfig {
            itemId = BR.item
        }
    }
}

class RecyclerViewExampleViewModel : BasePagesViewModel() {
    open val items: MutableLiveData<MutableList<IBindingModel>> = MutableLiveData()
}
      
      



, RV, , , , , presentation . , , , , .







Proses serupa untuk membuat adaptor untuk ViewPager dan ViewPager2 disajikan dalam contoh di github bersama dengan sumber terbuka, tautan yang saya posting di akhir artikel. Saat ini, perpustakaan masih dalam tahap penyelesaian, dan saya ingin menerima tanggapan dan harapan yang memadai untuk pengembangannya lebih lanjut. Ini juga mencakup fungsi tambahan untuk membuat penawaran dengan mudah, termasuk dalam hubungannya dengan ViewModel. (LayoutInflater.createBinding, Fragment.createBindingWithViewModel, dll.)





Terima kasih sudah membaca sampai akhir. Nikmati pengkodean dan suasana hati yang baik)








All Articles