在方向更改期间保存 Recycler 视图的实例
Saving the instance of Recycler view during orientation change
我有一个 RecyclerView
,它是使用 Arraylist
构建的。 Arraylist
由名为 ListItem
.
的用户定义对象组成
每个 recyclerview
都有卡片视图。每个 CardView
持有每个 ListItem
。
我从 RecyclerView
.
中删除了一个 CardView
当我旋转屏幕时,会创建一个新的 Activity,这会导致显示旧数据。但我希望 recyclerview
仅保持 updated list
并且应该 retain
scrolled position
.
列表项class:
class ListItem(var title: String, var info: String, val imageResource: Int) {
}
主要Activity class :
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()
}
}
我的适配器class:
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)
}
}
}
看起来 initializeData 被调用了两次,因为在方向改变时再次调用了 onCreate,您可以使用一些布尔值来检查数据是否已经初始化然后跳过初始化
你正在做的是删除传递给 recyclerview 的值,但是当方向改变时,recyclerview 从 activity 重新加载并且来自 activity 的原始数据再次传递下来没有任何变化,所以如果你想保存 recyclerview 中的更改,你必须更改 activity 中的原始数据,这样如果视图重新加载数据是相同的。
如果纵向和横向模式的布局相同,您可以限制 activity 在清单中重新启动。
将此添加到清单中的 activity。
<activity android:name=".activity.YourActivity"
android:label="@string/app_name"
android:configChanges="orientation|screenSize"/>
如果您不想限制屏幕方向的改变,那么您可以使用OnSaveInstanceState
方法在方向改变时保存您的旧数据。无论您通过此方法保存什么数据,您都将在 bundle
中的 OnCreate
方法中收到它。这是将 ArrayList 放入 Bundle 的帮助 . So here as you have ArrayList
of your own class type you also need to use Serializable or Parcelable。
除了这些使 ArrayList
成为 public static
始终是一个解决方案,但它在面向对象的参数中不是一个好的解决方案。在内存不足的情况下,它还会给您 NullPointerException
或数据丢失。
我认为你在 oncreate 方法中初始化适配器,其中将重新创建整个适配器,并且在配置更改时也会新创建所有数据。因为你在 oncreate 方法中初始化数据。尝试全局维护列表并在 activity 中删除列表中的项目,同时在适配器中删除。或者尝试类似视图模型架构
在项目中使用MVVM
模式。它将管理方向状态。
MVVM RecyclerView 示例:
https://medium.com/@Varnit/android-data-binding-with-recycler-views-and-mvvm-a-clean-coding-approach-c5eaf3cf3d72
我有一个 RecyclerView
,它是使用 Arraylist
构建的。 Arraylist
由名为 ListItem
.
每个 recyclerview
都有卡片视图。每个 CardView
持有每个 ListItem
。
我从 RecyclerView
.
CardView
当我旋转屏幕时,会创建一个新的 Activity,这会导致显示旧数据。但我希望 recyclerview
仅保持 updated list
并且应该 retain
scrolled position
.
列表项class:
class ListItem(var title: String, var info: String, val imageResource: Int) {
}
主要Activity class :
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()
}
}
我的适配器class:
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)
}
}
}
看起来 initializeData 被调用了两次,因为在方向改变时再次调用了 onCreate,您可以使用一些布尔值来检查数据是否已经初始化然后跳过初始化
你正在做的是删除传递给 recyclerview 的值,但是当方向改变时,recyclerview 从 activity 重新加载并且来自 activity 的原始数据再次传递下来没有任何变化,所以如果你想保存 recyclerview 中的更改,你必须更改 activity 中的原始数据,这样如果视图重新加载数据是相同的。
如果纵向和横向模式的布局相同,您可以限制 activity 在清单中重新启动。
将此添加到清单中的 activity。
<activity android:name=".activity.YourActivity"
android:label="@string/app_name"
android:configChanges="orientation|screenSize"/>
如果您不想限制屏幕方向的改变,那么您可以使用OnSaveInstanceState
方法在方向改变时保存您的旧数据。无论您通过此方法保存什么数据,您都将在 bundle
中的 OnCreate
方法中收到它。这是将 ArrayList 放入 Bundle 的帮助 ArrayList
of your own class type you also need to use Serializable or Parcelable。
除了这些使 ArrayList
成为 public static
始终是一个解决方案,但它在面向对象的参数中不是一个好的解决方案。在内存不足的情况下,它还会给您 NullPointerException
或数据丢失。
我认为你在 oncreate 方法中初始化适配器,其中将重新创建整个适配器,并且在配置更改时也会新创建所有数据。因为你在 oncreate 方法中初始化数据。尝试全局维护列表并在 activity 中删除列表中的项目,同时在适配器中删除。或者尝试类似视图模型架构
在项目中使用MVVM
模式。它将管理方向状态。
MVVM RecyclerView 示例: https://medium.com/@Varnit/android-data-binding-with-recycler-views-and-mvvm-a-clean-coding-approach-c5eaf3cf3d72