Headless Fragment 设计模式
Headless Fragment 的定义:没有UI的fragment。也就是说 onCreateView()
返回值为null
。通常配合setRetainInstance(true)
使用。后者可以让fragment在activity旋转重建时无需destroy。
为什么有 Headless Fragment这个概念,没有 view 的Fragment有什么功能呢?
在回答这两个问题之前,先回顾一下在面向对象编程中,代码复用的两种方式:
- 组合
- 继承
组合,我们可能会抽象出类似 utils、controller或者helper这种功能代码,业务逻辑是由这些功能代码块组合起来实现的。
优点:代码内聚,调用逻辑清晰可控。
缺点:是在Android端,需要注意太多的 Activity lifecycle细节,可能需要通过各种回调来处理跨生命周期的调用,而且还要注意防止内存泄漏。
继承,我们往往是在 BaseActivity 中实现公共功能,子类通过override、或者设置各种flag来实现功能的组合和差异化。
优点:Activity生命周期可感知,context获取方便
缺点:继承侵入性太大,“组合优于继承”,丧失了灵活性,无法处理跨越了 Activity 重建周期的事件回调。
Headless Fragment 在基于“组合”的代码复用方式的基础上,保留了“继承”复用的优点,同时回避了侵入性大等“继承”的缺点:
既有感知生命周期的能力(包括跨越activity重建周期的事件监听能力),也具有功能模块内聚性强,调用逻辑清晰的优点。
常见的使用场景:
-
Android M runtime permission request,封装成callback,避免在同一个 override 中处理各种权限业务。
-
将 startActivityForResult 的 override 调用形式,封装成 callback 形式调用。好处同上。
-
非侵入式的监听activity、fragment生命周期。
-
处理和生命周期有关的短期异步操作。注意只能是短期,长时间的异步操作建议还是通过AsyncTask或者HandlerThread。
很多常见的开源库都使用了这个小技巧:
-
通过
BindingFragment
监听activity的生命周期,并将LifecycleEvent
用BehaviorSubject
emit 出去。Observable.interval(0, 2, TimeUnit.SECONDS)
// ...
.compose(RxLifecycle.bind(this)
.<Long>disposeObservableWhen(LifecycleEvent.DESTROY_VIEW))
.subscribe();当然现在有了arch Lifecycle后,有了更好的实现方式。
-
Google Android Architecture 中的 ViewModel 实现
通过设置
HolderFragment.setRetainInstance(true)
,实现ViewModel
绑定Activity生命周期的同时,又跨越 Activity 重建过程。
-
通过
RxPermissionsFragment
将onRequestPermissionsResult
的override式调用转化为callback式调用。rxPermissions
.request(Manifest.permission.CAMERA)
.subscribe(granted -> {
if (granted) { // Always true pre-M
// I can control the camera now
} else {
// Oups permission denied
}
});
Author: deskid
Link: https://deskid.github.io/2019/03/08/headless-fragment/
License: 知识共享署名-非商业性使用 4.0 国际许可协议