原標題: Kotlin & RecyclerView for High Performance Lists in Androidhtml
原文地址: www.andreasjakl.comandroid
原文做者: Andreas Jaklgit
RecyclerView 是在 Android 上顯示滾動列表的最佳方法。它確保了高性能和平滑滾動,同時提供具備靈活佈局的列表元素。結合 Kotlin 的現代語言功能,與傳統的 Java 方法相比,RecyclerView 的代碼開銷大大下降。github
在本文中,咱們將介紹一個示例場景:維護應用程序的滾動列表,列出機器部件:「PartsList」。可是,此方案僅影響咱們使用的字符串 - 您能夠針對您須要的任何用例複製此方法。數組
要開始使用,請使用 Android Studio 3+ 建立一個新的 Android 應用。確保啓用 Kotlin 支持,併爲 MainActivity 選擇 「Empty」 模板。或者,若是您不想手動編寫如下步驟的代碼,請從 GitHub 下載完成的源碼。緩存
Android 中的屏幕列表由多個子視圖組成。每一個都有一個或多個視圖的佈局。例如,電子郵件應用會向您顯示多封電子郵件; 這些項目中的每一項都包括主題,發件人姓名和一堆其餘信息。bash
解析子視圖的 XML 佈局並將其擴展到類的實例中是一項消耗性能的操做。快速滑動會對手機性能形成巨大壓力。目標是始終堅持每秒60幀。可是,這每幀只剩下不到17毫秒的計算時間。架構
RecyclerView 的主要技巧是從新使用列表中的子視圖。一旦子視圖 滾出可見區域,它就基本上被放入隊列中。早晚,當新的子視圖滾動時會再次用到它。而後,子視圖的 UI 文本內容將被替換。下圖顯示了這個(簡化的)RecyclerView 原理:app
不幸的是,這種有效的方法須要一些架構背景。剛開始看起來可能感到陌生。然而,一旦您擁有全部組件,就能夠輕鬆的進行自定義。ide
使用RecyclerView須要配置/實現如下組件:
咱們的數據源是一個簡單的列表/數組。該列表由自定義類的實例組成。您能夠在應用程序中對這些進行硬編碼,也能夠動態建立它們 - 例如,基於來自在線源的 HTTP REST 請求。
Kotlin有一個很好的功能,能夠簡化數據類的編寫。此方法適用於僅包含數據但不包含任何操做的全部類。咱們的示例數據類稱爲 PartData
,由於它存儲有關維護應用程序的計算機部件的信息。
data class PartData ( val id: Long, val itemName: String)
複製代碼
對於數據類,Kotlin自動生成全部實用程序函數:
getter
和 setter
。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
的佈局。
對於示例用例,請使用如下屬性:
LinearLayout
(垂直)match_parent
wrap_content
16dp
接下來,將兩個子項添加到佈局中。咱們將使用 TextView的。只要確保你給他們有用的ID,由於咱們須要這些來分配Kotlin代碼中的文本:
使用 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的源代碼了。
首先,建立一個名爲 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 的新手,您可能想知道:咱們如何在 bind()
中訪問 itemView
?它從何而來?
魔術被稱爲主要構造函數。在 Kotlin 中,它能夠成爲類標題的一部分。前面的構造函數關鍵字是可選的。
class PartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { ... }
複製代碼
這有什麼好處的? Kotlin 自動將全部參數做爲屬性提供。所以,咱們沒有看到屬性定義和初始化。相反,咱們只是從 bind()
函數中訪問該屬性 。
咱們正在探索RecyclerView架構中最重要的組件:適配器。它有3個主要任務:
讓咱們看一下大圖中的適配器以及這3個任務適合的位置:
您沒必要編寫代碼來手動覆蓋這三個函數。只需擴展 PartAdapter 類的定義 便可。讓它繼承 RecyclerView 的適配器。Android Studio 會自動提示您實施全部必需的成員:
而後,將參數 「partItemList」 添加到 PartAdapter 類中。使用主構造函數。這將容許 MainActivity 在實例化 PartAdapter 時提供數據模型。
和之前同樣, partItemList 參數自動做爲屬性使用。在咱們的例子中,屬性類型是咱們的數據類的簡單列表(數組)。
class PartAdapter (val partItemList: List<PartData>, val clickListener: (PartData) -> Unit) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
複製代碼
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 複製代碼
inflate()
方法的最後一個參數 確保新視圖不會當即附加到父視圖組。相反,它只在緩存中,不該該是可見的。partItemList
屬性,咱們調用咱們添加到 ViewHolder 的自定義 bind()
函數。咱們差很少完成了。接下來,咱們建立 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" />
複製代碼
在MainActivity的 onCreate()
中只須要三行代碼 。
rv_parts.layoutManager = LinearLayoutManager(this)
複製代碼
rv_parts.hasFixedSize()
複製代碼
rv_parts.adapter = PartAdapter(testData)
複製代碼
如今按下播放,您的RecyclerView應該能夠正常工做!使用咱們提供的三個示例數據項,列表有點過短,沒法徹底理解滾動。要測試它,只需使用一些額外的項目擴展列表。
如今您已經掌握了基礎知識,能夠很容易地擴展項目佈局和數據類以及其餘信息。
若是某些內容不適合您,請將您的代碼與 GitHub 上的完成解決方案進行比較。請注意,解決方案比咱們在此階段更先進 - 例如,它已經包含單擊處理程序。
缺乏一個常用的部分:點擊處理程序。與 ListView 相比,這些在 RecyclerViews 中要複雜得多。可是,若是作得好,他們很容易添加 Kotlin。這只是瞭解一些更先進的 Kotlin 概念的問題。咱們將在下一部分看一下這個!