管理 RecyclerView 狀態

RecyclerView 可利用極少量圖像資源顯示大量資料。當使用者捲動瀏覽 RecyclerView 中的項目時,系統會重複使用捲動至螢幕外項目的 View 例項,以在螢幕上捲動時建立新項目。不過,設定變更 (例如裝置旋轉) 可能會重設 RecyclerView 的狀態,導致使用者必須再次捲動回項目清單中的先前位置。

每當設定變更時,RecyclerView 都應維持原本的狀態 (尤其是捲動位置),清單元素的狀態也不應變動。

維持狀態

設定 RecyclerView.Adapter 的狀態還原政策,儲存 RecyclerView 捲動位置。接著儲存 RecyclerView 清單項目的狀態。然後將清單項目的狀態新增至 RecyclerView 轉接程式,並在清單項目繫結至 ViewHolder 時還原清單項目狀態。

1. 啟用 Adapter 狀態還原政策

啟用 RecyclerView 轉接程式的狀態還原政策,以便在任何設定變更時保留 RecyclerView 的捲動位置。請將政策規格新增至轉接程式建構函式:

Kotlin

class MyAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. 儲存有狀態清單項目的狀態

儲存複雜 RecyclerView 清單項目的狀態,例如包含 EditText 元素的項目。舉例來說,如要儲存 EditText 的狀態,請新增與 onClick 處理常式類似的回呼,以擷取文字變更。然後在回呼中,定義要儲存的資料:

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {

    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

ActivityFragment 中宣告回呼。使用 ViewModel 儲存狀態。

3. 將清單項目狀態新增至 Adapter

將清單項目的狀態新增至 RecyclerView.Adapter。請在主機 ActivityFragment 建立時,將項目狀態傳遞至轉接程式建構函式:

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. 在轉接程式的 ViewHolder 中復原清單項目狀態

RecyclerView.Adapter 中,如果您將 ViewHolder 繫結至項目,請還原該項目的狀態:

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

重點

結果

RecyclerView 現在可以還原其捲動位置,以及 RecyclerView 清單中各項目的狀態。

包含此指南的集合

本指南是精選的快速指南系列之一,涵蓋更廣泛的 Android 開發目標:

讓應用程式支援平板電腦、折疊式裝置和 ChromeOS 裝置的最佳使用者體驗。

有問題或意見回饋嗎?

請前往常見問題頁面,瞭解快速指南或與我們聯絡,分享您的想法。