使用Moshi存取RecyclerView数据时Fragment切换卡顿如何优化?
性能优化方案
1. 核心卡顿原因定位
当前代码将磁盘IO(SharedPreferences读取)、JSON反序列化两个耗时操作全部放在主线程执行,Fragment切换时主线程需要负责UI渲染,耗时操作会阻塞主线程导致卡顿。
2. 代码优化方案
2.1 复用Moshi实例与JsonAdapter
当前每次调用save/load方法都会重复构建Moshi实例、反射生成JsonAdapter,这两个对象可以全局复用,避免重复的反射解析开销:
// 提为Fragment成员变量,懒加载仅初始化一次 private val sharedPreferences by lazy { requireContext().getSharedPreferences("recycler_view", Context.MODE_PRIVATE) } private val moshi by lazy { Moshi.Builder() .add(BigDecimalAdapter) .add(KotlinJsonAdapterFactory()) .build() } private val cardListJsonAdapter by lazy { val listType = Types.newParameterizedType(List::class.java, CardItem::class.java) moshi.adapter<ArrayList<CardItem>>(listType) }
2.2 异步执行数据存取操作
将耗时的IO、序列化/反序列化操作放到后台线程执行,避免阻塞主线程,推荐使用Android官方协程实现:
// 异步加载数据 private fun loadDataAsync() = lifecycleScope.launch(Dispatchers.IO) { val json = sharedPreferences.getString("data_list", null) val loadedData = json?.let { cardListJsonAdapter.fromJson(it) } ?: arrayListOf() // 切回主线程更新UI withContext(Dispatchers.Main) { dataList = loadedData adapter.updateData(loadedData) // 自行在Adapter中实现updateData方法更新列表 } } // 异步保存数据 private fun saveDataAsync() = lifecycleScope.launch(Dispatchers.IO) { val json = cardListJsonAdapter.toJson(dataList) sharedPreferences.edit() .putString("data_list", json) .apply() }
2.3 调整RecyclerView初始化顺序
不需要等待数据加载完成再初始化RecyclerView,先初始化UI组件,数据加载完成后再更新Adapter即可:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 先初始化RecyclerView recyclerView = rootView.findViewById(R.id.main_recycler_view) recyclerView.setHasFixedSize(true) recyclerView.layoutManager = LinearLayoutManager(requireContext()) adapter = MainAdapter(arrayListOf(), this) recyclerView.adapter = adapter // 异步加载数据,加载完成后更新Adapter loadDataAsync() }
3. 进阶优化方案
- 给
CardItem类添加@JsonClass(generateAdapter = true)注解,开启Moshi代码生成能力,无需反射即可生成适配器,反序列化性能可提升30%以上,同时可以移除KotlinJsonAdapterFactory依赖。 - 引入ViewModel缓存加载完成的列表数据,Fragment因切换销毁重建时,直接从ViewModel取缓存数据,无需重复执行SP读取和反序列化操作。
- 若数据量超过百条级别,建议替换SharedPreferences为Jetpack DataStore或Room数据库,SharedPreferences本身不适合存储大体积JSON字符串,读写性能远低于专门的存储组件。
内容的提问来源于stack exchange,提问作者Tom Darious
相关产品推荐
相关产品推荐

