Android MongoDB Realm采用异步查询仍出现掉帧卡顿的问题咨询
代码存在的核心问题
你当前的实现即使使用了Realm的异步查询接口,依然会在主线程产生大量耗时操作,是导致卡顿、触发跳帧提示的直接原因,具体问题如下:
- 数据集同步逻辑完全错误:
findAllAsync()返回的RealmResults<ShopItem>是可自动更新的动态代理数据集,本身会在查询完成、数据变更时触发回调。你在onChange回调中执行shopItemList.addAll(shopItems)的操作,会在每次回调时全量遍历整个查询结果,把Realm代理对象拷贝到自定义的静态ArrayList中。这部分遍历、对象拷贝的逻辑完全运行在主线程上,数据量稍大就会直接占用主线程执行时间,造成掉帧;同时还会导致数据重复添加的逻辑bug,用户能明显看到列表内容重复堆叠。 - 全量刷新适配器的开销过大:你在拿到数据后直接调用
notifyDataSetChanged(),会强制RecyclerView重绘所有可见的列表item,没有任何增量更新优化,列表item数量多的时候,所有item的测量、布局、绘制逻辑都会堆积在主线程同一帧执行,很容易触发Skipped frames的系统提示。 - 监听器未做生命周期管控:当前给查询结果注册的变更监听器没有和页面生命周期、Realm实例的销毁逻辑绑定,不仅会造成内存泄漏,还可能在页面已经退出的场景下依然触发数据回调,进一步堆积主线程任务。
可落地的修正方案
- 移除自定义的静态ArrayList,直接将
RealmResults<ShopItem>作为RecyclerView适配器的数据源。RealmResults本身实现了List接口,会自动同步数据变化,完全不需要手动做对象拷贝,直接省掉主线程上的遍历拷贝开销。 - 替换原生的RecyclerView适配器为Realm官方提供的
RealmRecyclerViewAdapter,它会自动监听数据集的变化,完成增量的列表刷新,不需要手动调用notifyDataSetChanged(),大幅降低列表刷新时的主线程开销。 - 给查询结果的变更监听器绑定页面生命周期:在页面
onStart阶段注册监听器,在onStop阶段移除监听器,避免无意义的回调触发。 - 注意:如果使用了
deleteRealmIfMigrationNeeded()配置,Realm.getInstance()首次执行时会有删除旧数据库、重建数据库文件的IO开销,这部分逻辑如果直接在主线程执行也会造成启动阶段卡顿,可以将Realm实例的初始化逻辑提前放到后台线程完成,减少主线程的初始化耗时。
内容的提问来源于stack exchange,提问作者Junn Dobit Paras
相关产品推荐
相关产品推荐

