【问题标题】:Saving the instance of Recycler view during orientation change在方向更改期间保存 Recycler 视图的实例
【发布时间】:2019-07-02 06:36:40
【问题描述】:

我有一个RecyclerView,它是使用Arraylist 构建的。 Arraylist 由名为 ListItem 的用户定义对象组成。

每个recyclerview 都有一个卡片视图。每个CardView 包含每个ListItem。 我从那个RecyclerView 中删除了一个CardView

当我旋转屏幕时,会创建一个新的 Activity,从而显示旧数据。但我希望 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)
        }
    }
}

【问题讨论】:

标签: android android-recyclerview orientation-changes onconfigurationchanged scroll-position


【解决方案1】:

如果纵向和横向模式的布局相同,您可以在 Manifest 中限制 Activity 重新启动。

将此添加到清单中的活动中。

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

如果您不想限制屏幕方向更改,则可以在方向更改时使用OnSaveInstanceState 方法保存旧数据。无论您通过此方法保存的任何数据,您都将在OnCreatebundle 方法中收到它。这是帮助link。所以在这里你有你自己的类类型的ArrayList,你还需要使用SerializableParcelable将你的ArrayList放在你的Bundle中。

除了这些使ArrayList 成为public static 始终是一个解决方案,但它在面向对象的paratime 中不是一个好的解决方案。在内存不足的情况下,它还可以为您提供NullPointerException 或数据丢失。

【讨论】:

  • 我有不同的纵向和横向 UI 设计。使用此功能时,当我将屏幕从横向更改为纵向时,横向的相同 UI 设计也适用于纵向。
  • 如果有帮助,请接受我的回答。或者如果您需要进一步的帮助,请告诉我。
【解决方案2】:

看起来initializeData被调用了两次,因为onCreate在方向改变时被再次调用,你可以使用一些布尔值来检查数据是否已经被初始化然后跳过初始化

【讨论】:

    【解决方案3】:

    您正在做的是删除向下传递给 recyclerview 的值,但是当方向更改时,recyclerview 从活动重新加载,并且活动的原始数据再次向下传递并且没有任何变化,所以如果你想保存recyclerview 中的更改您必须更改活动中的原始数据,以便在视图重新加载时数据是相同的。

    【讨论】:

      【解决方案4】:

      我认为你在 oncreate 方法中初始化适配器,在该方法中,整个适配器将被重新创建,并且所有数据也会在配置更改时重新创建。因为你在 oncreate 方法中初始化数据。尝试全局维护列表,并在您也删除适配器时删除活动列表中的项目。或者尝试像视图模型架构这样的东西

      【讨论】:

        【解决方案5】:

        在项目中使用MVVM 模式。它将管理方向状态。

        MVVM RecyclerView 示例: https://medium.com/@Varnit/android-data-binding-with-recycler-views-and-mvvm-a-clean-coding-approach-c5eaf3cf3d72

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-02-09
          • 2011-10-29
          • 1970-01-01
          • 2011-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多