Сохранение экземпляра представления Recycler при изменении ориентации

У меня есть RecyclerView, который был собран с использованием Arraylist. Этот Arraylist состоит из определяемых пользователем объектов с именами ListItem.

Каждый recyclerview имеет представление карты. Каждый CardView содержит каждый ListItem. Я удалил один CardView из этого RecyclerView.

Когда я поворачиваю экран, создается новое действие, в результате которого отображаются старые данные. Но я хочу, чтобы recyclerview содержал только updated list и должен retain содержать scrolled position.

Класс ListItem :

class ListItem(var title: String, var info: String,  val imageResource: Int) { 

}

Класс MainActivity :

class MainActivity : AppCompatActivity() {
    private lateinit var mSportsData: ArrayList<ListItem>
    private lateinit var mAdapter: MyAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val gridColumnCount = resources.getInteger(R.integer.grid_column_count)
        recycler_view.layoutManager = GridLayoutManager(this,gridColumnCount)
        mSportsData = ArrayList()
        recycler_view.setHasFixedSize(true)
        initializeData()
        recycler_view.adapter = mAdapter

        var swipeDirs = 0
        if (gridColumnCount <= 1) {
            swipeDirs = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
        }

        val helper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN,swipeDirs) {
            override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
                val from = viewHolder.adapterPosition
                val to = target.adapterPosition
                Collections.swap(mSportsData,from,to)
                mAdapter.notifyItemMoved(from,to)
                return true
            }
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                mSportsData.removeAt(viewHolder.adapterPosition)
                mAdapter.notifyItemRemoved(viewHolder.adapterPosition)
            }
        })
        helper.attachToRecyclerView(recycler_view)
    }

    private fun initializeData() {
        val sportsList : Array<String> = resources.getStringArray(R.array.sports_titles)
        Log.d("Printing","$sportsList")
        val sportsInfo : Array<String> = resources.getStringArray(R.array.sports_info)
        val sportsImageResources : TypedArray = resources.obtainTypedArray(R.array.sports_images)

        mSportsData.clear()

        for (i in sportsList.indices-1) {
            Log.d("Printing","${sportsList[i]},${sportsInfo[i]},${sportsImageResources.getResourceId(i,0)}")
            mSportsData.add(ListItem(sportsList[i], sportsInfo[i], sportsImageResources.getResourceId(i, 0)))
        }
        sportsImageResources.recycle()
        mAdapter = MyAdapter(mSportsData,this)
        mAdapter.notifyDataSetChanged()
    }

    fun resetSports(view: View) {
        initializeData()
    }
}

Класс MyAdapter :

class MyAdapter(var mSportsData: ArrayList<ListItem>, var context: Context) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(LayoutInflater.from(context).inflate(R.layout.wordlist_item,parent,false))
    }

    override fun getItemCount() = mSportsData.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val listItem = mSportsData.get(position)
        holder.bindTo(listItem)
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
        init {
            itemView.setOnClickListener(this)
        }
        override fun onClick(view: View) {
            val currentSport = mSportsData.get(adapterPosition)
            val detailIntent = Intent(context, DetailActivity::class.java)
            detailIntent.putExtra("title", currentSport.title)
            detailIntent.putExtra("image_resource", currentSport.imageResource)
            context.startActivity(detailIntent)
        }
        fun bindTo(currentSport : ListItem){
            itemView.heading_textview.setText(currentSport.title)
            itemView.description_textview.setText(currentSport.info)
            Glide.with(context).load(currentSport.imageResource).into(itemView.image_view)
        }
    }
}

person Shaheen Ahamed S    schedule 02.07.2019    source источник
comment
Следуйте этому - stackoverflow.com/a/42662482   -  person Anupam    schedule 02.07.2019


Ответы (5)


Похоже, что initializeData вызывается дважды, так как onCreate снова вызывается при изменении ориентации, вы можете использовать какое-то логическое значение, чтобы проверить, были ли данные уже инициализированы, а затем пропустить инициализацию

person Alexey    schedule 02.07.2019

Вы можете ограничить перезапуск активности в своем манифесте, если у вас одинаковый макет для портретного и альбомного режимов.

Добавьте это в свою активность в манифесте.

 <activity android:name=".activity.YourActivity"
    android:label="@string/app_name"
    android:configChanges="orientation|screenSize"/>

Если вы не хотите ограничивать изменения ориентации экрана, вы можете использовать метод OnSaveInstanceState для сохранения старых данных при изменении ориентации. Какие бы данные вы ни сохранили с помощью этого метода, вы получите их в своем методе OnCreate в bundle. Вот вспомогательная ссылка. Итак, здесь, поскольку у вас есть ArrayList вашего собственного типа класса, вам также необходимо использовать Serializable или Parcelable, чтобы поместить ваш ArrayList в ваш Bundle.

За исключением того, что создание ArrayList как public static всегда является решением, но это не очень хорошее решение в объектно-ориентированном паратайме. Это также может привести к NullPointerException или потере данных в случае нехватки памяти.

person Asad Ali Choudhry    schedule 02.07.2019
comment
У меня разный дизайн пользовательского интерфейса для портрета и ландшафта. При использовании этого, когда я меняю экран с альбомного на портретный, тот же дизайн пользовательского интерфейса, что и в альбомном, применяется и для портретного. - person Shaheen Ahamed S; 02.07.2019
comment
если это поможет, пожалуйста, примите мой ответ. или дайте мне знать, если вам нужна дополнительная помощь. - person Asad Ali Choudhry; 03.07.2019

Что вы делаете, так это удаляете значения, которые передаются в recyclerview, но когда ориентация изменяется, recyclerview перезагружается из действия, а исходные данные из действия снова передаются, и ничего не меняется, поэтому, если вы хотите сохранить изменения в recyclerview вам нужно изменить исходные данные в действии, чтобы при перезагрузке представления данные были одинаковыми.

person raj kavadia    schedule 02.07.2019

Я думаю, вы инициализируете адаптер в методе oncreate, в котором весь адаптер будет воссоздан, и все данные также будут созданы заново при изменении конфигурации. Потому что вы инициализируете данные в методе oncreate. Попробуйте что-нибудь глобально сохранить список, а также удалить элемент в списке в действии, когда вы также удаляете в адаптере. Или попробуйте что-то вроде архитектуры модели просмотра

person Karthick Ramanathan    schedule 02.07.2019

Используйте шаблон MVVM в проекте. Он будет управлять состоянием ориентации.

Пример MVVM RecyclerView: https://medium.com/@Varnit/android-data-binding-with-recycler-views-and-mvvm-a-clean-coding-approach-c5eaf3cf3d72

person Afinas EM    schedule 02.07.2019