Headless Fragment 的定义:没有UI的fragment。也就是说 onCreateView()返回值为null。通常配合setRetainInstance(true)使用。后者可以让fragment在activity旋转重建时无需destroy。

为什么有 Headless Fragment这个概念,没有 view 的Fragment有什么功能呢?

在回答这两个问题之前,先回顾一下在面向对象编程中,代码复用的两种方式:

  1. 组合
  2. 继承

组合,我们可能会抽象出类似 utils、controller或者helper这种功能代码,业务逻辑是由这些功能代码块组合起来实现的。

优点:代码内聚,调用逻辑清晰可控。
缺点:是在Android端,需要注意太多的 Activity lifecycle细节,可能需要通过各种回调来处理跨生命周期的调用,而且还要注意防止内存泄漏。

继承,我们往往是在 BaseActivity 中实现公共功能,子类通过override、或者设置各种flag来实现功能的组合和差异化。

优点:Activity生命周期可感知,context获取方便
缺点:继承侵入性太大,“组合优于继承”,丧失了灵活性,无法处理跨越了 Activity 重建周期的事件回调。

Headless Fragment 在基于“组合”的代码复用方式的基础上,保留了“继承”复用的优点,同时回避了侵入性大等“继承”的缺点:

既有感知生命周期的能力(包括跨越activity重建周期的事件监听能力),也具有功能模块内聚性强,调用逻辑清晰的优点。

常见的使用场景:

  1. Android M runtime permission request,封装成callback,避免在同一个 override 中处理各种权限业务。

  2. 将 startActivityForResult 的 override 调用形式,封装成 callback 形式调用。好处同上。

  3. 非侵入式的监听activity、fragment生命周期。

  4. 处理和生命周期有关的短期异步操作。注意只能是短期,长时间的异步操作建议还是通过AsyncTask或者HandlerThread。

很多常见的开源库都使用了这个小技巧:

  • RxLifecycle

    通过BindingFragment监听activity的生命周期,并将LifecycleEventBehaviorSubject 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 重建过程。

  • RxPermissions

    通过RxPermissionsFragmentonRequestPermissionsResult 的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
    }
    });