是时候在 Android 中抛弃 Loader 了

简评:我个人是没有试过在项目里大规模使用 Loader,如果你知道有基于 Loader 的大型项目或者库的话,可以交流下。: )

Loader 在 2011 年左右和 Android Honycomb 被一起推出。曾经是一个实际上不应该出现的问题的解决办法 - 如果在 Fragment 或 Activity 中执行异步任务时遇到了 configuration 变化。

但 Fragment 或 View 中应该只表示应用程序的状态和处理交互,而不去运行任何异步业务逻辑。

所以,Loader 是想要解决哪些问题?

  • Loader 运行在单独的线程上,以免出现 UI 无响应。

  • 当有事件触发时,提供回调方法以简化线程管理。

  • Loader 能够保留并缓存数据,以免当 configuration 变化后重复查询。

  • Loader 能通过实现 observer 来观察底层数据源的变动。比如,CursorLoader 会自动注册一个 ContentObserver,从而在数据变动时触发 reload。

事实上,这些情况在今天都不能让你一定要用 Loader,所有这些都可以在你不「潜入」LoaderManager 这个黑盒子的情况下解决。

现在通过 Architecture Components 中的 ViewModel 可以更方便的解决跨 configuration 的数据缓存和持久化问题,其不受设备横竖屏切换影响,也可以很方便的直接调用 onCleared() 方法取消对数据的订阅,防止内存泄漏。

使用 Loader 还需要注意 Activity 和 Fragment 的生命周期,要在适当的时候提供结果。同样,Architecture Components 中的 LiveData 可以满足需求,其对生命周期敏感,只在数据发生变化并且有被监听的时候触发。结合 Room 你甚至可以不额外增加一行代码就实现对数据库数据变动的监听。同时,Google 也强烈建议使用 Room 而不是直接使用 SQLite 和避免使用 Cursor(Square 的 SQL Brite 也有同样的作用)。

Loader 最大的问题可能就是「鼓励」你把异步代码放到 Fragment 或者说 UI 层当中(Fragment 中很多代码都是为了支持 Loader)。

到目前 Google 只提供了 CursorLoader 和 AsyncTaskLoader 这两个 Loader 的实现类,或许也侧面证明了 Loader 的复杂。Mark Murphy('The Busy Coder's Guide to Android Development' 的作者) 曾经尝试基于 Loader 实现一个库,但最终还是放弃了,并写了一篇很棒的文章来解释为什么。

此外,Loader 的相关代码还深深的包含在 Activity 和 Fragment 中,不能用 JUnit 来测试。

最近,Android Support Library 27.1.0 中也开始减少 Fragment 和 Loader 的耦合了。或许,是时候选择更好的替代方案了。

是时候在 Android 中抛弃 Loader 了