← Назад к вопросам

Как можно у RecyclerView сохранить состояние скролла при пересоздании Activity?

1.0 Junior🔥 242 комментариев
#Android компоненты#Жизненный цикл и навигация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сохранение состояния скролла RecyclerView

Для сохранения состояния скролла RecyclerView при пересоздании Activity необходимо управлять состоянием макета (layout state), которое включает позицию скролла, состояние элементов и другие параметры. Вот основные подходы:

1. Сохранение состояния в Bundle

Самый распространенный метод - использование onSaveInstanceState() и restoreInstanceState().

class MainActivity : AppCompatActivity() {
    private lateinit var recyclerView: RecyclerView
    private val KEY_RECYCLER_STATE = "recycler_state"
    private var recyclerViewState: Parcelable? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        recyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = MyAdapter()
        
        // Восстановление состояния после пересоздания
        savedInstanceState?.let {
            recyclerViewState = it.getParcelable(KEY_RECYCLER_STATE)
        }
    }

    override fun onResume() {
        super.onResume()
        // Восстанавливаем состояние после onResume
        recyclerViewState?.let {
            recyclerView.layoutManager?.onRestoreInstanceState(it)
            recyclerViewState = null
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        // Сохраняем состояние RecyclerView
        recyclerView.layoutManager?.let {
            outState.putParcelable(KEY_RECYCLER_STATE, it.onSaveInstanceState())
        }
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        // Альтернативный способ восстановления состояния
        recyclerViewState = savedInstanceState.getParcelable(KEY_RECYCLER_STATE)
    }
}

2. Использование ViewModel

ViewModel сохраняется при изменении конфигурации, что позволяет сохранять состояние:

class MyViewModel : ViewModel() {
    var recyclerViewState: Parcelable? = null
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = MyAdapter()
        
        // Восстановление из ViewModel
        viewModel.recyclerViewState?.let {
            recyclerView.layoutManager?.onRestoreInstanceState(it)
        }
    }
    
    override fun onPause() {
        super.onPause()
        // Сохранение в ViewModel
        viewModel.recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
    }
}

3. Автоматическое сохранение с RecyclerView

Начиная с Support Library 24+, RecyclerView может автоматически сохранять состояние:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:saveEnabled="true"
    app:layoutManager="linear" />

Но для полного контроля лучше использовать явное сохранение.

4. Сохранение состояния вложенных RecyclerView

Для сложных случаев с вложенными RecyclerView или горизонтальными списками:

class NestedRecyclerViewState {
    companion object {
        private val statesMap = mutableMapOf<String, Parcelable>()
        
        fun saveState(recyclerViewId: Int, state: Parcelable) {
            statesMap[recyclerViewId.toString()] = state
        }
        
        fun restoreState(recyclerViewId: Int): Parcelable? {
            return statesMap[recyclerViewId.toString()]
        }
    }
}

// Использование в адаптере вложенного RecyclerView
inner class NestedAdapter : RecyclerView.Adapter<NestedViewHolder>() {
    override fun onBindViewHolder(holder: NestedViewHolder, position: Int) {
        holder.nestedRecyclerView.layoutManager?.let { lm ->
            val savedState = NestedRecyclerViewState.restoreState(holder.itemView.id)
            savedState?.let { lm.onRestoreInstanceState(it) }
        }
    }
}

5. Решение проблем с конфигурацией

При изменении конфигурации (поворот экрана) важно:

  • Сохранять позицию скролла точно
  • Сохранять состояние элементов (чекбоксы, прогресс-бары)
  • Учитывать перезагрузку данных из сети/БД
// Дополнительное сохранение позиции
private var scrollPosition = 0

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    
    recyclerView.layoutManager?.let { lm ->
        if (lm is LinearLayoutManager) {
            scrollPosition = lm.findFirstVisibleItemPosition()
            outState.putInt("scroll_position", scrollPosition)
        }
    }
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    
    scrollPosition = savedInstanceState.getInt("scroll_position", 0)
    recyclerView.scrollToPosition(scrollPosition)
}

Ключевые моменты:

  1. LayoutManager.onSaveInstanceState() - основной метод сохранения состояния
  2. ViewModel предпочтительнее для сложных сценариев
  3. При работе с асинхронной загрузкой данных сохраняйте состояние после полной загрузки
  4. Для динамически изменяемых списков учитывайте изменение размера данных
  5. Тестируйте поведение при быстрых поворотах экрана

Лучшие практики:

  • Всегда очищайте ссылки на состояние после восстановления
  • Используйте уникальные ключи для Bundle
  • При работе с Fragment сохраняйте состояние в onSaveInstanceState() Fragment
  • Для реализации бесконечного скролла сохраняйте загруженные данные и позицию

Правильное сохранение состояния RecyclerView улучшает пользовательский опыт, делая навигацию плавной и предсказуемой при пересоздании Activity.

Как можно у RecyclerView сохранить состояние скролла при пересоздании Activity? | PrepBro