آموزش کار با Epoxy در اندروید - قسمت ۱

Epoxy
Epoxy

توی این مقاله قرار بگیم Epoxy چیه و چکارهایی می تونه برای ما انجام بده یا به عبارت دیگه چطور زندگی برامون راحت تر کنه :)

تقریبا برای همون پیش اومده که بخوایم لیست های پیچیده توی اندروید پیاده سازی کنیم خب راه حلی که براش بود اینه که بیایم برای recycler view مون تایپ های متفاوتی تعریف کنیم و لیست ها بر اون اساس پیاده سازی کنیم جدا از چالش هایی که اون حالت داره کلی boilerplate هم داریم حالا با epoxy میشه این کار ساده تر انجام داد در واقع شعارش هم همین پیاده سازی لیست های پیچیده به سادگی هست.


این لایبری توسط شرکت Airbnb و برای پیاده سازی صفحات پیچیده با recycler view توسعه داده شده است.


بریم که شروع کنیم :

دو مفهوم در epoxy خیلی مهم هستند :

اول ) Epoxy Model : آیتم های Recycler.ViewHolder کنترل می کند و در واقع کار اصلیش اینه که یک کلاس مدل را برای هر آیتم ایجاد می کند تا دیتا های مربوط به آن ها را نمایش بدهد. ضمنا یک کلاس immutable هست و کاری شبیه به view model انجام میدهد دیتا دریافتی برای نمایش به view میدهد.

دوم ) Epoxy Controller : مشخص میکنه که کدام مدل ها باید به recyclerView برای نمایش اضافه شوند و از این طریق یک صفحه پیچیده کاملا ساده پیاده سازی کنیم.


به سه روش زیر می توان Epoxy Model را ایجاد کرد : (در این مقاله از روش سوم استفاده می کنیم)

۱ - custom view

۲- data binding

۳- view holder


اول epoxy به پروژه امون اضافه می کنیم :

apply plugin: 'kotlin-kapt' 

kapt {
    correctErrorTypes = true
}

dependencies {
      implementation  'com.airbnb.android:epoxy:3.6.0' 
     kapt 'com.airbnb.android:epoxy-processor:3.6.0'
}

بعد از اون آیتم های لیست رو می سازیم :

<?xml version=&quot1.0&quot encoding=&quotutf-8&quot?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quothttp://schemas.android.com/apk/res/android&quot
    android:layout_width=&quotwrap_content&quot
    android:layout_height=&quot56dp&quot
    xmlns:app=&quothttp://schemas.android.com/apk/res-auto&quot>

    <TextView
        android:id=&quot@+id/title&quot
        android:layout_width=&quotwrap_content&quot
        android:layout_height=&quotwrap_content&quot
        android:text=&quotHello World!&quot
        app:layout_constraintBottom_toBottomOf=&quotparent&quot
        app:layout_constraintLeft_toLeftOf=&quotparent&quot
        app:layout_constraintRight_toRightOf=&quotparent&quot
        app:layout_constraintTop_toTopOf=&quotparent&quot />

</androidx.constraintlayout.widget.ConstraintLayout>

و بعد نوبت خود epoxy که به ui اکتیویتی اضافه بشه :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quothttp://schemas.android.com/apk/res/android&quot
    xmlns:app=&quothttp://schemas.android.com/apk/res-auto&quot
    xmlns:tools=&quothttp://schemas.android.com/tools&quot
    android:layout_width=&quotmatch_parent&quot
    android:layout_height=&quotmatch_parent&quot
    tools:context=&quot.MainActivity&quot>

   <com.airbnb.epoxy.EpoxyRecyclerView
       android:id=&quot@+id/headerList&quot
       android:layout_width=&quotmatch_parent&quot
       android:layout_height=&quotmatch_parent&quot
       />

</androidx.constraintlayout.widget.ConstraintLayout>

در مرحله بعد باید بریم و Epoxy Model را درست کنیم که طبق چیزی که قبلا گفتیم ما از روش view holder استفاده می کنیم :

@EpoxyModelClass(layout = R.layout.header_view)
abstract class HeaderViewWithViewHolderEpoxy : EpoxyModelWithHolder<Holder>(){

    @EpoxyAttribute lateinit var title : String

    override fun bind(holder: Holder) {
        holder.title.text = title
    }

}

class Holder:KotlinHolder() {
        val title by bind<TextView>(R.id.title)
}

همون طور که می بینید توی خط اول و از طریق انوتیشن EpoxyModelClass لایه ای که باید infleted بشه رو بهش معرفی می کنیم.

توی متد bind هم دیتا دریافتی از طریق EpoxyAttribute ها به ویو bind میکنه.

اگه از java استفاده می کنید که view holder شبیه به همون view holder ریسایکلر ویو هست فقط از EpoxyHolder ارث بری می کند.

اما برای kotlin میشه کلاس KotlinHolder به پروژه اضافه کرد و خیلی راحت از اون استفاده کنیم.

حالا که epoxy model ما ساخته شد به یک epoxy controller احتیاج داریم که برای نمایش باید به اون اضافه شود.

class HeaderViewController : EpoxyController() {
    
    override fun buildModels() {
      HeaderViewWithKotlinModelEpoxy(&quotfood&quot) 
      .id(1)// به هر آیتم باید یک ایدی نسبت داده شود
     .addTo(this) / /  به این طریق مدل به کنترلر اضافه می کنیم
      HeaderViewWithKotlinModelEpoxy(&quotgame&quot).id(2).addTo(this)
      HeaderViewWithKotlinModelEpoxy(&quotcode&quot).id(3).addTo(this)
    }
}

هر کنترلر یک متد buildModels داره که از طریق اون مشخص میشه که چه آیتم هایی باید نمایش داده شوند. نکته خوب epoxy درواقع همین جاست که توی این متد cotroller هر model که قبلا ساخته باشیم می شه گذاشت و کاملا داینامیک هست.(در این مثال فقط از یک model استفاده شده اما از هر چندmodel که بخواهیم میتونم استفاده کنیم.)

یه حالت هم داره برای تعریف دو تایپ که در این لینک می تونید بیشتر بخونید.

دیگه فقط قسمت اخرش مونده که اینو به ریسایکلر مون معرفی کنیم تا لیست مورد نظر ما رو نمایش بده

val controller = HeaderViewController()
controller.isDebugLoggingEnabled = true // برای دیباگ کردن و چک کردن لیست بسیار کاربردی هست اما ضروری نیست.

headerList.apply {
    layoutManager = LinearLayoutManager(this@MainActivity,LinearLayoutManager.VERTICAL,false)
    adapter = controller.adapter
    controller.requestModelBuild() // برای زمانی که دیتا تغییر می کنه استفاده میشود.
}

هر کنترلر یک adaper داره که برای ست کردن adapter ریسایکلر ویو می تونیم از اون استفاده کنیم.

متد requestModelBuild زمانی که دیتا تغییر کنه دوباره buildModel فراخوانی میکنه تا تغییرات جدید به مدل ها بایند شده و آپدیت شوند.

حالا ما از epoxy برای پروژه امون استفاده کردیم.

چیزی که epoxy برای من جذاب تر کرد قسمت کاتلینش بود که توی مقاله بعدی با یه کلاس ساده تر و خیلی راحت modelهامون می سازیم و استفاده می کنیم.

داکیومنت خود epoxy که لینکش توی قسمت منابع اومده خیلی کامل تر توضیح داده و پیشنهاد میکنم حتما مطالعه کنید.

قسمت دوم

منابع :

https://github.com/airbnb/epoxy/wiki
https://android.jlelse.eu/simplifying-recycler-view-with-epoxy-in-kotlin-nachos-tutorial-series-946d22116d57