Android jetpack 架构组件复习----Lifecycle

88 阅读5分钟

Android jetpack涉及到的组件:

jetpack.png

一、Lifecycle

androidx.lifecycle 软件包提供了可用于构建生命周期感知型组件的类和接口 - 这些组件可以根据 activity 或 fragment 的当前生命周期状态自动调整其行为。

Lifecycle Lifecycle 是一个类,用于存储有关组件(如 activity 或 fragment)的生命周期状态的信息,并允许其他对象观测此状态。

Lifecycle 使用两种主要枚举跟踪其关联组件的生命周期状态:

事件

从框架和 Lifecycle 类分派的生命周期事件。这些事件映射到 activity 和 fragment 中的回调事件。

状态

Lifecycle 对象所跟踪的组件的当前状态。

lifecycle.png

您可以将状态看作图中的节点,将事件看作这些节点之间的边。

类可以通过实现 DefaultLifecycleObserver 并替换相应的方法(如 onCreate 和 onStart 等)来监控组件的生命周期状态。然后,您可以通过调用 Lifecycle 类的 addObserver() 方法并传递观测者的实例来添加观测者,如下例所示:

class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        connect()
    }

    override fun onPause(owner: LifecycleOwner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

Lifecycle 的实现机制是观察者模式,整体上知道了这个,再讲它的使用过程就比较容易理解了:

  1. 构建一个 Lifecycle 对象(通过一个实现了 LifecycleOwner 接口的对象的 getLifecycle()方法返回),这个对象就是一个被观察者,具有生命周期感知能力
  2. 构建一个 LifecycleObserver 对象,它是观察者,它对指定的 Lifecycle 对象进行监听
  3. 通过将 Lifecycle 对象的 addObserver(…) 方法,添加观察者,将 Lifecycle 对象和 LifecycleObserver 对象进行绑定

可以看到,我们通过在方法上使用@OnLifecycleEvent 注解使得该方法具有了生命周期感知能力。括号里面的参数,表明需要监听的是什么生命周期事件。

一个例子:


import android.app.Activity;
import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

/**
 * 获取用户的地理位置
 */
public class MyLocationListener implements LifecycleObserver {
    private String TAG = this.getClass().getName();
    private Activity context;
    private OnLocationChangedListener onLocationChangedListener;

    public MyLocationListener(Activity context, OnLocationChangedListener onLocationChangedListener) {
        this.context = context;
        this.onLocationChangedListener = onLocationChangedListener;
    }

    /**
     * 当Activity 执行onResume()方法时,该方法会被自动调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation()");
    }

    /**
     * 当Activity 执行onPause()方法时,该方法会被自动调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void stopGetLocation() {
        Log.d(TAG, "stopGetLocation()");
    }

    /**
     * 当地理位置发生变化时,通过该接口通知调用者
     */
    public interface OnLocationChangedListener {
        void onChanged(double latitude, double longitude);
    }
    // 其他一些业务代码
}


import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private MyLocationListener myLocationListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myLocationListener = new MyLocationListener(this, new MyLocationListener.OnLocationChangedListener() {
            @Override
            public void onChanged(double latitude, double longitude) {
                // 展示收到的位置信息
            }
        });
        // 将观察者与被观察者绑定
        getLifecycle().addObserver(myLocationListener);
    }
}

运行代码,当Activity处于对应的生命周期时,就会执行对应的方法,如上面的注释所写。

/**
 * 当Activity 执行onResume()方法时,该方法会被自动调用
 */
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void startGetLocation() {
    Log.d(TAG, "startGetLocation()");
}

二、LifecycleOwner

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

support library 26.1.0 及以后的支持库中,AppCompatActivity 的祖先类 SupportActivity已经默认实现了 LifecycleOwner 接口,通过其 getLifecycle() 方法可以直接返回一个 Lifecycle 对象。之后我们就可以通过该对象的 addObserver(…) 方法将 Lifecycle 跟指定的 LifecycleObserver 进行绑定。

如果您有一个自定义类并希望使其成为 LifecycleOwner,您可以使用 LifecycleRegistry 类,但需要将事件转发到该类,如以下代码示例中所示:

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
    }
}

一个来自其它文章的例子:

public class MainActivity extends Activity implements LifecycleOwner {

    private LifecycleRegistry mLifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLifecycleRegistry = new LifecycleRegistry(this);
        getLifecycle().addObserver(new MyObserver());
        mLifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mLifecycleRegistry.markState(Lifecycle.State.RESUMED);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mLifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
}


MainActivity实现了LifecycleOwner接口(实现该接口的对象,即是 Lifecycle 的持有者),并在其 getLifecycle( ) 方法中返回了一个 LifecycleRegistry对象,而 LifecycleRegistry 是 Lifecycle 的子类。其他使用方式,则完全相同。

总结

  1. 实现了 LifecycleObserver 接口的类可以和实现了 LifecycleOwner 接口的类无缝工作,因为 LifecycleOwner 可以提供一个 Lifecycle 对象,而 LifecycleObserver 就正需要对这个 Lifecycle 对象进行监听呢。

  2. LifecycleOwner 是从特定的类(比如 Activity 或者 Fragment 等)中抽象出来的Lifecycle 的持有者。

  3. LifecycleRegistry 类用于注册和反注册需要观察当前组件生命周期的 LifecycleObserver

最佳实践

有关生命周期感知型组件的最佳实践

  • 使界面控制器(activity 和 fragment)尽可能保持精简。它们不应试图获取自己的数据,而应使用 ViewModel 执行此操作,同时应观测 LiveData 对象以在视图中体现相应变化。

  • 设法编写数据驱动型界面,在此类界面中,界面控制器负责随着数据的更改更新视图,或者向 ViewModel 通知用户的操作。

  • 将数据逻辑放在 ViewModel 类中。ViewModel 应充当界面控制器与应用其余部分之间的连接器。不过要注意,ViewModel 不负责获取数据(例如,从网络获取)。但是,ViewModel 应调用相应的组件来提取数据,然后将结果提供给界面控制器。

  • 使用数据绑定在视图与界面控制器之间维持干净的接口。这样可以让视图更具声明性,并尽量减少需要在 activity 和 fragment 中编写的更新代码。如果您更愿意使用 Java 编程语言来达成此目的,请使用 Butter Knife 之类的库,以避免样板代码并实现更好的抽象化。

  • 如果界面很复杂,不妨考虑创建 presenter 类来处理界面的修改。这可能是一项艰巨的任务,但这样做可使界面组件更易于测试。

  • 避免在 ViewModel 中引用 View 或 Activity 上下文。如果 ViewModel 存在的时间比 activity 更长(在配置更改的情况下),activity 将泄漏并且不会获得垃圾回收器的妥善处置。

  • 使用 Kotlin 协程管理长时间运行的任务和其他可以异步运行的操作。