Loading

重新学习Android——(三)LifeCycle组件

业务逻辑与生命周期耦合产生的问题

规约,这里我提到“组件”,是指Android SDK API中包含生命周期的那些类,比如ActivityServiceFragment等。

组件有其生命周期,比如Activity的onCreateonStoponStart

当我们编写组件时,很多操作往往依赖于组件的这些生命周期,比如我们需要在Activity onStart时开启位置监听,onStop时关闭位置监听,我们很可能写出这样的代码:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        
        locationListener = MyLocationListener(this) {
          // do something else...
        }
    }

    override fun onStart() {
        super.onStart()
        locationListener.start()
    }

    override fun onStop() {
        super.onStop()
        locationListener.stop()
    }

}

编写这样的代码可能会出现三个问题

第一个就是:如果业务复杂度增加,组件中依赖生命周期的代码很快就会多到难以控制。根据关注点分离原则,这些代码应该被移到别处。

override fun onStart() {
    super.onStart()
    locationListener.start()
    xxxListener.start()
    yyyListener.start()
    zzzListener.start()
}

override fun onStop() {
    super.onStop()
    locationListener.stop()
    xxxListener.stop()
    yyyListener.stop()
    zzzListener.stop()
}

override fun onXXX() {
    //...
}

override fun onYYY() {
    //...
}

第二个问题,如果这些相同的逻辑在其他组件中也需要,相同的代码要写好多份

class FirstActivity : AppCompatActivity() {
    // ...
    override fun onStart() {
        super.onStart()
        locationListener.start()
    }

    override fun onStop() {
        super.onStop()
        locationListener.stop()
    }
}
class SecondActivity : AppCompatActivity() {
    // ...
    override fun onStart() {
        super.onStart()
        locationListener.start()
    }

    override fun onStop() {
        super.onStop()
        locationListener.stop()
    }
}

第三个问题,如何保证调用顺序真的是按照生命周期进行调用的?

public override fun onStart() {
    super.onStart()
    Util.checkUserStatus { result ->
        // 如果这个回调在`onStop`后被调用会发生什么?
        if (result) {
            myLocationListener.start()
        }
    }
}

public override fun onStop() {
    super.onStop()
    myLocationListener.stop()
}

如上的代码很可能引发内存泄漏或者直接让程序崩溃。

Lifecycle库

Lifecycle是Jetpack中的一个库,它存在的目的就是为了解决之前我们的业务逻辑和组件的生命周期紧紧耦合所带来的一系列麻烦。

Lifecycle类

Lifecycle类用来表示组件的生命周期状态,还允许其它对象观察此状态。它的公共方法就三个:

就是说可以向Lifecycle添加一些观察者,观察者会接收到Lifecycle的事件,并且可以通过getCurrentState方法来获取当前事件。

我们可以从具有生命周期的组件中直接使用lifecycle属性获取这个lifecycle对象,在Java中,可以通过getLifecycle方法来获取。

LifecycleOwner

当我们点击到上面的getLifecycle方法的源代码中去时,我们发现,它是一个重载方法。

该方法来自LifecycleOwner接口

androidx中的FragmentAppCompatActivity等这些组件都已经实现了LifecycleOwner接口,所以刚刚我们才可以直接在其中使用getLifecycle方法。

官方说法: 支持库 26.1.0 及更高版本中的 Fragment 和 Activity 已实现 LifecycleOwner 接口。

抽象出这么个东西有啥好处呢?好处大大滴有!我来缕一缕。

我们之前需要的是将组件中与生命周期相关的操作和组件解耦,比如,我们不想再在Activity中看到这样的代码:

fun onStart() {
    xxxListener.start()
    yyyListener.start()
    zzzListener.start()
}

这些代码的问题就是,像Activity之类的组件必须主动承担所有根据其生命周期对其他类库进行调节的工作,根据分离关注点原则,这些操作应当由其他类来完成。

而每个LifecycleOwner都持有的Lifecycle实例正暴露了addObserver方法,让程序中的其他类能够向其添加观察者,让其他类能够主动去观察组件生命周期的改变。

// 继承自androidx中的AppCompatActivity,所以天生就是LifecycleOwner
class MainActivity : AppCompatActivity() {

    lateinit var locationListener: MyLocationListener

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 添加生命周期观察者,`locationListener`现在可以观察并跟随`MainActivity`的生命周期
        lifecycle.addObserver(locationListener)
        
    }

}

LifecycleObserver

下面让我们来看看Lifecycle版图中的最后一块,观察者——LifecycleObserver

LifecycleObserver是一个接口,它长这样:

没错,它就长这样。。。它里面没有任何方法,那观察个屁啊?

诶?忘了最上面的注释,上面写着:

不要直接使用这个接口将一个类标记为一个LifecycleObserver,换做实现DefaultLifecycleObserverLifecycleEventObserver去接收生命周期事件的通知。

DefaultLifecycleObserver里面就有方法了,它提供了所有的生命周期事件的回调,并且默认情况下都是什么都不做。

public interface DefaultLifecycleObserver extends FullLifecycleObserver {

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) { }

    @Override
    default void onStart(@NonNull LifecycleOwner owner) { }

    @Override
    default void onResume(@NonNull LifecycleOwner owner) { }

    @Override
    default void onPause(@NonNull LifecycleOwner owner) { }

    @Override
    default void onStop(@NonNull LifecycleOwner owner) { }

    @Override
    default void onDestroy(@NonNull LifecycleOwner owner) { }
}

LifecycleEventObserver更加直接,它直接提供了一个onStateChanged方法,所有的生命周期事件都会在这里被接受到

public interface LifecycleEventObserver extends LifecycleObserver {
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

当有某几个生命周期事件中有一些通用代码时,这将会很好用。

总之,Lifecycle库通过这几个核心类将之前的Activity等组件主动承担调配类库在指定生命周期下的行为转换成了类库主动去承担这些责任,这样不就解耦并把关注点给分离了吗。

示例代码

class MyLocationListener(
    private val context: Context,
    private val callback: (Location) -> Unit
) : DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) {
        super.onStart(owner)
        // do something
    }

    override fun onStop(owner: LifecycleOwner) {
        super.onStop(owner)
        // do something
    }


}
class MainActivity : AppCompatActivity() {

    lateinit var locationListener: MyLocationListener

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        locationListener = MyLocationListener(this) {
            // update ui
        }

        lifecycle.addObserver(locationListener)

    }

}

这里我们成功把关注点从MainActivity中移到了MyLocationListener

自定义LifecycleOwner(官方示例)

class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

生命周期感知型组件的最佳做法(官方)

  • 使界面控制器(Activity 和 Fragment)尽可能保持精简。它们不应试图获取自己的数据,而应使用 ViewModel 执行此操作,并观察 LiveData 对象以将更改体现到视图中。
  • 设法编写数据驱动型界面,对于此类界面,界面控制器的责任是随着数据更改而更新视图,或者将用户操作通知给 ViewModel。
  • 将数据逻辑放在 ViewModel 类中。ViewModel 应充当界面控制器与应用其余部分之间的连接器。不过要注意,ViewModel 不负责获取数据(例如,从网络获取)。但是,ViewModel 应调用相应的组件来获取数据,然后将结果提供给界面控制器。
  • 使用数据绑定在视图与界面控制器之间维持干净的接口。这样一来,您可以使视图更具声明性,并尽量减少需要在 Activity 和 Fragment 中编写的更新代码。如果您更愿意使用 Java 编程语言执行此操作,请使用诸如 Butter Knife 之类的库,以避免样板代码并实现更好的抽象化。
  • 如果界面很复杂,不妨考虑创建 presenter 类来处理界面的修改。这可能是一项艰巨的任务,但这样做可使界面组件更易于测试。
  • 避免在 ViewModel 中引用 View 或 Activity 上下文。如果 ViewModel 存在的时间比 Activity 更长(在配置更改的情况下),Activity 将泄漏并且不会获得垃圾回收器的妥善处置。
  • 使用 Kotlin 协程管理长时间运行的任务和其他可以异步运行的操作。

生命周期感知型组件的用例 (官方)

生命周期感知型组件可使您在各种情况下更轻松地管理生命周期。下面列举几个例子:

  • 在粗粒度和细粒度位置更新之间切换。使用生命周期感知型组件可在位置应用可见时启用细粒度位置更新,并在应用位于后台时切换到粗粒度更新。借助生命周期感知型组件 LiveData,应用可以在用户使用位置发生变化时自动更新界面。
  • 停止和开始视频缓冲。使用生命周期感知型组件可尽快开始视频缓冲,但会推迟播放,直到应用完全启动。此外,应用销毁后,您还可以使用生命周期感知型组件终止缓冲。
  • 开始和停止网络连接。借助生命周期感知型组件,可在应用位于前台时启用网络数据的实时更新(流式传输),并在应用进入后台时自动暂停。
  • 暂停和恢复动画可绘制资源。借助生命周期感知型组件,可在应用位于后台时暂停动画可绘制资源,并在应用位于前台后恢复可绘制资源。

参考

posted @ 2022-01-01 20:59  yudoge  阅读(369)  评论(0编辑  收藏  举报