[譯]Android 中 Kotlin 與 RecyclerView 高性能列表

翻譯說明:

原標題: Kotlin & RecyclerView for High Performance Lists in Androidhtml

原文地址: www.andreasjakl.comandroid

原文做者: Andreas Jaklgit

RecyclerView 是在 Android 上顯示滾動列表的最佳方法。它確保了高性能和平滑滾動,同時提供具備靈活佈局的列表元素。結合 Kotlin 的現代語言功能,與傳統的 Java 方法相比,RecyclerView 的代碼開銷大大下降。github

示例項目:PartsList - 入門

在本文中,咱們將介紹一個示例場景:維護應用程序的滾動列表,列出機器部件:「PartsList」。可是,此方案僅影響咱們使用的字符串 - 您能夠針對您須要的任何用例複製此方法。數組

要開始使用,請使用 Android Studio 3+ 建立一個新的 Android 應用。確保啓用 Kotlin 支持,併爲 MainActivity 選擇 「Empty」 模板。或者,若是您不想手動編寫如下步驟的代碼,請從 GitHub 下載完成的源碼緩存

什麼是 RecyclerView?

Android 中的屏幕列表由多個子視圖組成。每一個都有一個或多個視圖的佈局。例如,電子郵件應用會向您顯示多封電子郵件; 這些項目中的每一項都包括主題,發件人姓名和一堆其餘信息。bash

解析子視圖的 XML 佈局並將其擴展到類的實例中是一項消耗性能的操做。快速滑動會對手機性能形成巨大壓力。目標是始終堅持每秒60幀。可是,這每幀只剩下不到17毫秒的計算時間。架構

RecyclerView 的主要技巧是從新使用列表中的子視圖。一旦子視圖 滾出可見區域,它就基本上被放入隊列中。早晚,當新的子視圖滾動時會再次用到它。而後,子視圖的 UI 文本內容將被替換。下圖顯示了這個(簡化的)RecyclerView 原理:app

RecyclerView流程

不幸的是,這種有效的方法須要一些架構背景。剛開始看起來可能感到陌生。然而,一旦您擁有全部組件,就能夠輕鬆的進行自定義。ide

使用RecyclerView須要配置/實現如下組件:

  • RecyclerView:管理一切。它主要由Android預先編寫。您提供組件和配置。
  • Adapter:您將花費大部分時間編寫此類。它鏈接到數據源。在RecyclerView的指示下,它會建立或更新列表中的各個項目。
  • ViewHolder:一個簡單的類,用於分配/更新視圖項中的數據。從新使用視圖時,將覆蓋先前的數據。
  • Data source:您喜歡的任何東西 - 從簡單的數組到完整的數據源。您的適配器與之交互。
  • LayoutManager:負責將全部單獨的視圖項放在屏幕上,並確保它們得到所需的屏幕空間。

數據源和Kotlin數據類

咱們的數據源是一個簡單的列表/數組。該列表由自定義類的實例組成。您能夠在應用程序中對這些進行硬編碼,也能夠動態建立它們 - 例如,基於來自在線源的 HTTP REST 請求。

Kotlin有一個很好的功能,能夠簡化數據類的編寫。此方法適用於僅包含數據但不包含任何操做的全部類。咱們的示例數據類稱爲 PartData,由於它存儲有關維護應用程序的計算機部件的信息。

data class PartData ( val id: Long, val itemName: String)
複製代碼

對於數據類,Kotlin自動生成全部實用程序函數:

  • 屬性:您再也不須要像普通 Java 那樣編寫 gettersetter
  • 附加功能:例如,equals()hasCode()toString()copy()

Antonio Leiva 寫了一篇很棒的文章,在相同數據類的狀況下將 Java 與 Kotlin 進行比較。您能夠節省大約80%的代碼並仍然獲得相同的結果。

您像任何其餘類同樣實例化 Kotlin 數據類。請注意,Kotlin 不使用 new語句,所以咱們只使用類名並將值提供給構造函數參數。添加該代碼的nCreate() 您的 MainActivity。

var partList = ArrayList<PartData>()
partList.add(PartData(100411, "LED Green 568 nm, 5mm"))
partList.add(PartData(101119, "Aluminium Capacitor 4.7μF"))
partList.add(PartData(101624, "Potentiometer 500kΩ"))
// ...

複製代碼

列表項目佈局

RecyclerView 中的每一個項目都須要自定義佈局。您可使用任意與 Activity 佈局相同的方式建立這個文件:在 Android Studio 的 Android-style 項目視圖中,打開 app > res > layout。右鍵單擊"layout"文件夾名稱,而後選擇 New > Layout resource file。建立一個名爲part_list_item.xml的佈局。

對於示例用例,請使用如下屬性:

  • Layout: LinearLayout (垂直)
  • Width: match_parent
  • Height: wrap_content
  • Padding: 16dp

接下來,將兩個子項添加到佈局中。咱們將使用 TextView的。只要確保你給他們有用的ID,由於咱們須要這些來分配Kotlin代碼中的文本:

  • Id 1: @+id/tv_part_item_name (larger text size)
  • Id 2: @+id/tv_part_id (smaller text size)

Recycler View Dependencies

使用 Android 5.0(API級別21)將 RecyclerView 添加到 Android 系統中。許多應用程序仍然針對 Android 4.4+,所以您一般會經過 AppCompat / Support 庫使用 RecyclerView 。將最新的支持庫版本(取決於您的編譯SDK)包含到應用程序構建build的依賴項中 .gradle 文件。

implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0'
複製代碼

在咱們添加了這個定義以後,咱們能夠開始編寫使用RecyclerView的源代碼了。

ViewHolder:處理列表中的單個項目

首先,建立一個名爲 PartAdapter 的類 。將其放在與 MainActivity 相同的目錄中 。在這個類中,建立一個名爲 PartViewHolder嵌套類

class PartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun bind(part: PartData) {
        itemView.tv_part_item_name.text = part.itemName
        itemView.tv_part_id.text = part.id.toString()
    }
}
複製代碼

該 ViewHolder 介紹了項目視圖。此外,它還在 RecyclerView 中存儲其位置的元數據。

本質上,咱們的 ViewHolder 實現的主要任務是將當前須要的數據綁定到先前膨脹的UI佈局。每當滾動期間新項目可見時,此類確保項目的視圖顯示咱們指望在列表中此位置的內容。

要更新 UI,咱們建立本身的方法並將其命名爲 bind()。請注意,這不是基類的重寫方法,所以咱們能夠給它任何名稱。做爲方法參數,咱們只須要在 UI 中顯示數據。在 bind() 中,咱們只是將提供的數據分配給視圖項。

(從技術上講,咱們沒有綁定它,咱們只是分配數據。若是數據模型發生變化,它將不會自動更新此實現中的可見列表。)

Kotlin:主要構造函數

若是您是 Kotlin 的新手,您可能想知道:咱們如何在 bind() 中訪問 itemView?它從何而來?

魔術被稱爲主要構造函數。在 Kotlin 中,它能夠成爲類標題的一部分。前面的構造函數關鍵字是可選的。

class PartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { ... }
複製代碼

這有什麼好處的? Kotlin 自動將全部參數做爲屬性提供。所以,咱們沒有看到屬性定義和初始化。相反,咱們只是從 bind() 函數中訪問該屬性 。

RecyclerView適配器:將它固定在一塊兒

咱們正在探索RecyclerView架構中最重要的組件:適配器。它有3個主要任務:

讓咱們看一下大圖中的適配器以及這3個任務適合的位置:

  1. 爲了在屏幕上繪製列表,RecyclerView 將詢問適配器總共有多少項。咱們的適配器在 getItemCount() 中返回此信息 。
  2. 每當 RecyclerView 決定它須要內存中的另外一個視圖實例時,它將調用 onCreateViewHolder()。在此方法中,適配器會膨脹並返回咱們在上一步中建立的xml佈局。
  3. 每次(從新)使用先前建立的 ViewHolder 時,RecyclerView 都會指示適配器更新其數據。咱們經過重寫 onBindViewHolder() 來自定義此過程 。

您沒必要編寫代碼來手動覆蓋這三個函數。只需擴展 PartAdapter 類的定義 便可。讓它繼承 RecyclerView 的適配器。Android Studio 會自動提示您實施全部必需的成員:

而後,將參數 「partItemList」 添加到 PartAdapter 類中。使用主構造函數。這將容許 MainActivity 在實例化 PartAdapter 時提供數據模型。

和之前同樣, partItemList 參數自動做爲屬性使用。在咱們的例子中,屬性類型是咱們的數據類的簡單列表(數組)。

class PartAdapter (val partItemList: List<PartData>, val clickListener: (PartData) -> Unit) :
        RecyclerView.Adapter<RecyclerView.ViewHolder>() {
複製代碼

RecyclerView的適配器實現

Android Studio 已經建立了方法存根。咱們只需編寫幾行實現。此代碼根據咱們的要求定製適配器,並完成我所描述的3個主要任務。

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    // LayoutInflater: takes ID from layout defined in XML.
    // Instantiates the layout XML into corresponding View objects.
    // Use context from main app -> also supplies theme layout values!
    val inflater = LayoutInflater.from(parent.context)
    // Inflate XML. Last parameter: don't immediately attach new view to the parent view group val view = inflater.inflate(R.layout.part_list_item, parent, false) return PartViewHolder(view) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { // Populate ViewHolder with data that corresponds to the position in the list // which we are told to load (holder as PartViewHolder).bind(partItemList[position]) } override fun getItemCount() = partItemList.size 複製代碼
  • onCreateViewHolder():擴展視圖項的佈局XML。inflate() 方法的最後一個參數 確保新視圖不會當即附加到父視圖組。相反,它只在緩存中,不該該是可見的。
  • onBindViewHolder():在 RecyclerView 提供全部必要的信息-在 ViewHolder 實例應顯示的數據,以及在數據列表中的(新)位置。使用咱們的 Adapter 類的 partItemList 屬性,咱們調用咱們添加到 ViewHolder 的自定義 bind()函數。
  • getItemCount():在咱們的例子中簡單 - 列表/數組的大小。在 Kotlin中,咱們能夠進一步將其簡化爲內聯實現; 若是咱們直接返回一個值/一個簡單的表達式,咱們不須要函數的 {} 和 return 語句。

RecyclerViews的活動佈局

咱們差很少完成了。接下來,咱們建立 RecyclerView。第一步是將其添加到 MainActivity 的 XML 佈局定義中。

若是您使用 Android Studio 的新項目嚮導並建立了一個空活動,則會添加一個 「Hello World」 TextView。刪除它。

而是爲具備ID 「rv_parts」 的滾動全屏 RecyclerView 列表添加如下定義:

<android.support.v7.widget.RecyclerView
        android:id="@+id/rv_parts"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
複製代碼

實例化RecyclerView

在MainActivity的 onCreate() 中只須要三行代碼 。

  1. 分配LayoutManager:它測量和定位項目視圖。不一樣的佈局管理器支持各類佈局。咱們選擇最多見的:LinearLayoutManager。默認狀況下,它會建立垂直滾動列表佈局。
rv_parts.layoutManager = LinearLayoutManager(this)
複製代碼
  1. 優化:所述 RecyclerView 的大小是不會被影響適配器內容。RecyclerView 的大小僅取決於父級(在咱們的示例中,全屏可用)。 所以,咱們能夠調用 setHasFixedSize() 來激活 RecyclerView 中的一些優化。在 Kotlin 中,您不須要 「set」-prefix 來訪問屬性。
rv_parts.hasFixedSize()
複製代碼
  1. 分配適配器:這最終鏈接全部內容:咱們建立並分配咱們編寫的Adapter類的新實例(「PartAdapter」)。該適配器須要的數據項,這是咱們在本文開頭建立的列表。
rv_parts.adapter = PartAdapter(testData)
複製代碼

RecyclerView:工做!

如今按下播放,您的RecyclerView應該能夠正常工做!使用咱們提供的三個示例數據項,列表有點過短,沒法徹底理解滾動。要測試它,只需使用一些額外的項目擴展列表。

如今您已經掌握了基礎知識,能夠很容易地擴展項目佈局和數據類以及其餘信息。

若是某些內容不適合您,請將您的代碼與 GitHub 上的完成解決方案進行比較。請注意,解決方案比咱們在此階段更先進 - 例如,它已經包含單擊處理程序。

下一步:單擊「處理程序」

缺乏一個常用的部分:點擊處理程序。與 ListView 相比,這些在 RecyclerViews 中要複雜得多。可是,若是作得好,他們很容易添加 Kotlin。這只是瞭解一些更先進的 Kotlin 概念的問題。咱們將在下一部分看一下這個!

歡迎關注 Kotlin 中文社區!

中文官網:www.kotlincn.net/

中文官方博客:www.kotliner.cn/

公衆號:Kotlin

知乎專欄:Kotlin

CSDN:Kotlin中文社區

掘金:Kotlin中文社區

簡書:Kotlin中文社區

相關文章
相關標籤/搜索