如何重构RecyclerView代码接入ViewModel和LiveData实现数据跨重启保存恢复
实现步骤
1. 改造RecyclerAdapter支持动态数据更新
原有Adapter传入的是不可变列表,无法后续更新数据,我们调整为可变列表并新增提交数据的方法:
class RecyclerAdapter(private val listener: OnRecyclerClickListener) : RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder>() { private var recyclerList = emptyList<RecyclerCard>() // 新增提交数据方法,更新列表后刷新UI fun submitList(newList: List<RecyclerCard>) { recyclerList = newList notifyDataSetChanged() // 数据量大的话可以替换为DiffUtil提升性能 } // 原有ViewHolder、点击接口、onCreateViewHolder、onBindViewHolder逻辑保持不变 inner class RecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener { val recyclerImageView: AppCompatImageView = itemView.findViewById(R.id.recycler_picture_image_view) val recyclerTitleView: AppCompatTextView = itemView.findViewById(R.id.recycler_title_text_view) val recyclerScoreView: AppCompatTextView = itemView.findViewById(R.id.recycler_score_text_view) init { itemView.setOnClickListener(this) } override fun onClick(v: View?) { val position = adapterPosition if (position != RecyclerView.NO_POSITION) { listener.onRecyclerClick(position) } } } interface OnRecyclerClickListener { fun onRecyclerClick(position: Int) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder { val itemView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_card, parent, false) return RecyclerViewHolder(itemView) } override fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) { val currentRecycler = recyclerList[position] Glide.with(holder.itemView.context) .load(currentRecycler.recyclerImage) .apply(RequestOptions.skipMemoryCacheOf(true)) .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE)) .into(holder.recyclerImageView) holder.recyclerTitleView.text = currentRecycler.recyclerTitle holder.recyclerScoreView.text = currentRecycler.recyclerScore } override fun getItemCount(): Int = recyclerList.size }
2. 给数据实体类添加序列化能力
要持久化存储RecyclerCard数据,需要让它支持序列化,这里以实现Serializable为例:
import java.io.Serializable data class RecyclerCard( val recyclerImage: String, val recyclerTitle: String, val recyclerScore: String, val extra: String // 对应你原来的第四个参数string3 ) : Serializable
3. 实现ViewModel+LiveData管理数据
ViewModel负责持有数据、处理逻辑、持久化存储,LiveData负责通知UI更新。这里用SharedPreferences+Gson实现轻量持久化,适合数据量不大的场景:
import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.gson.Gson import com.google.gson.reflect.TypeToken import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class MainViewModel(application: Application) : AndroidViewModel(application) { // 持有的列表数据,LiveData可被UI层观察 val cardList = MutableLiveData<ArrayList<RecyclerCard>>() private val sp = application.getSharedPreferences("recycler_data", 0) private val gson = Gson() init { // 初始化时先读本地存储的缓存数据 loadCacheData() } // 读取本地缓存 private fun loadCacheData() { val jsonStr = sp.getString("card_list", null) ?: return val type = object : TypeToken<ArrayList<RecyclerCard>>() {}.type val cacheList = gson.fromJson<ArrayList<RecyclerCard>>(jsonStr, type) cardList.postValue(cacheList) } // 新增卡片数据,同时更新本地缓存 fun addCard(card: RecyclerCard) { viewModelScope.launch(Dispatchers.IO) { val currentList = cardList.value ?: arrayListOf() currentList.add(card) // 存到本地 sp.edit() .putString("card_list", gson.toJson(currentList)) .apply() // 通知UI更新 cardList.postValue(currentList) } } // 你如果有删除、修改数据的需求,同样在这里处理并同步更新本地存储即可 }
4. 改造Fragment只做UI交互
Fragment不再持有数据,只负责初始化UI、观察LiveData变化、触发ViewModel的操作:
class Main : Fragment(), RecyclerAdapter.OnRecyclerClickListener { private lateinit var mainRecyclerView: RecyclerView private lateinit var adapter: RecyclerAdapter // 初始化ViewModel,和Fragment生命周期绑定 private val viewModel by viewModels<MainViewModel>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mainRecyclerView = view.findViewById(R.id.main_recycler_view) // 初始化adapter和RecyclerView adapter = RecyclerAdapter(this) mainRecyclerView.adapter = adapter mainRecyclerView.layoutManager = LinearLayoutManager(requireContext()) mainRecyclerView.setHasFixedSize(true) // 观察ViewModel的列表数据,变化时自动更新adapter viewModel.cardList.observe(viewLifecycleOwner) { newList -> adapter.submitList(newList) } // 原来的IO逻辑移到ViewModel中执行,避免内存泄漏 viewModel.addCard( RecyclerCard( string1, string2, score, string3 ) ) } override fun onRecyclerClick(position: Int) { // 原有点击逻辑保持不变 } }
补充说明
- ViewModel本身可以解决配置变更(如屏幕旋转、语言切换)时的数据不丢失问题,搭配SharedPreferences/Room等本地持久化方案才能实现应用彻底关闭后重启仍然恢复数据的需求
- 如果你的数据量较大、有复杂查询需求,推荐将持久化逻辑替换为Room数据库,性能和稳定性更好
- 代码中用到Gson需要提前在build.gradle中引入依赖,
notifyDataSetChanged可以替换为DiffUtil实现局部刷新,提升列表滑动性能
内容的提问来源于stack exchange,提问作者Tom Darious
相关产品推荐
相关产品推荐

