天天看點

【Android】使用Epoxy替代RecyclerView.AdapterEpoxy開發流程0. gradle1. cell layout2. package-info.java3. EpoxyController4. use in RecyclerView總結

【Android】使用Epoxy替代RecyclerView.AdapterEpoxy開發流程0. gradle1. cell layout2. package-info.java3. EpoxyController4. use in RecyclerView總結

Epoxy

Epoxy通過聲明式的方式幫助RecyclerView更高效的實作資料加載、UI更新等邏輯,提高清單場景的開發效率。

https://github.com/airbnb/epoxy

Epoxy is an Android library for building complex screens in a RecyclerView - airbnb/epoxy

開發流程

Epoxy的基本使用流程:

  1. 建立cell的layout檔案

    可以使用

    .xml

    、或者

    .kt

    建立cell的layout。推薦使用xml,搭配databinding使用起來更簡單。
  2. 根據cell生成EpoxyModel

    在package-info.java中聲明layout檔案、kapt根據xml自動生成EpoxyModel代碼,供EpoxyRecyclerView使用

  3. 建立EpoxyController

    EpoxyController相當于RecyclerView的Adapter,用來将資料綁定到UI,同時定義OnClick等事件

  4. 使用EpoxyController

    将EpoxyController設定到EpoxyRecyclerView,完成清單的資料記載和顯示

接下來簡單介紹一下每一步的具體實作。例如我們需要在清單中加載下列資料:

data class Foo (
    var title: String,
    var bar: List<Bar>
)

data class Bar (
    var body: String,
    var time: String  
)
           

0. gradle

apply plugin: 'kotlin-kapt' // 需要使用kapt

android {
 dataBinding {
        enabled = true // 使用databinding
    }
}

kapt {
    correctErrorTypes = true
}

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

1. cell layout

list_cell_a.xml

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

    <data>
        <variable
            name="title"
            type="String"
            />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{title}"
            android:textSize="24sp"
            android:textStyle="bold"
            tools:text="test"
            />

    </LinearLayout>

</layout>
           

list_cell_b.xml

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

    <data>

        <variable
            name="body"
            type="String"
            />

        <variable
            name="time"
            type="String"
            />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="8dp"
        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{body}"
            android:textSize="20sp"
            tools:text="test"
            />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{time}"
            android:textSize="18sp"
            tools:text="test"
            />
    </LinearLayout>

</layout>
           

2. package-info.java

@EpoxyDataBindingLayouts({
        R.layout.list_cell_a,
        R.layout.list_cell_b
})
package com.airbnb.epoxy.sample;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;
           

編譯後,會根據layout檔案,生成

EpoxyModels

代碼,例如

ListCellABindingModel_

ListCellBindingModel_

等,用來綁定資料

3. EpoxyController

繼承

TypedEpoxyController

,重寫

buildmodels

,用聲明式的方式填充UI的資料。

class FooBarController : TypedEpoxyController<Foo>() {
    override fun buildModels(foo: Foo) {

        ListCellABindingModel_()
            .title(foo.title) // databinding
            .id(modelCountBuiltSoFar)
            .addTo(this)

        foo.bar.forEach {
            ListCellBindingModel_()
                    .body(it.body)
                    .time(it.time)
                    .id(modelCountBuiltSoFar)
                    .addTo(this)
        }
    }
}
           
  • 根據buildModels參數個數選擇不同基類,例如

    Typed2EpoxyController

    Typed3EpoxyController

  • title

    body

    time

    是layout的定義的

    databinding

  • id

    用來區分不同類型的Cell,所有的EpoxyModels必須有唯一id

4. use in RecyclerView

class FooBarFragment : Fragment() {
    lateinit var binding: FragmentFooBarBinding //fragment的layout生成的daabinding
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_foo_bar, container, false)
        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val controller = FooBarController()
        binding.recyclerView.adapter = controller.adapter

        val data = Foo("title", listOf(Bar("str1","time1"),Bar("str2","time2")))
        controller.setData(data)
    })
}
           

通過Controller中設定data,資料将自動在渲染到清單中

總結

通過簡單的執行個體,可以感覺到Epoxy有以下幾個好處

  1. 避免了ViewHolder的使用, 代碼更少
  2. 通過EpoxyController和EpoxyModel,聲明式的填充資料到UI,簡單直覺
  3. 每次資料更新後,會自動diff最小量重新整理UI(類似pagging的功能)
  4. 配合MvRx使用,實作完整的響應式UI