Lifecycles

本文是对lifecycles原文的学习和翻译。也会加入一些自己的体会。如果你有足够的耐心,就会发现其实没接触之前再难的东西,当你花足够的时间去了解它,你会发现没有什么能难倒你 。附上原文地址:Handling lifecycles with lifecycle-aware components | Android Developers

使用生命周期感知组件来处理生命周期

根据文章标题来看,我们对android各大组件的生命周期都不陌生,但是这里有一个新的概念——生命周期感知组件。这里说白了,就是有这样一个组件如果实现了android.arch.lifecycle提供的接口就能感知如activity/fragment这样的组件的生命周期,当在开发中某个类要依赖生命周期操作就可以这样处理。

感知生命周期的组件可以执行某个动作,以响应其他组件(activity/fragmrnt)的生命周期状态的变化。这些组件有助于产生更好的组织性和更轻量的代码,也更易于维护。

现在的开发中,有一种常见的业务需求。比如某一个业务逻辑,要在activity/fragment的某个生命周期中来完成,这样的方式很容易导致代码的错误扩大化以及影响代码可读性。通过使用生命周期感知组件,可以将依赖组件生命周期的代码从生命周期方法中移出来,这样就减少了某些风险,增加代码可读性。

android.arch.lifecycle提供的类和接口可以让你构建能感知生命周期(lifecycle-aware)的类。所谓可以感知生命周期就是能够感知Activity或者Fragment的生命周期并且可以自行调整类的行为。

那么在我们工程中怎样来依赖呢,根据自己的需要可以选择你想用的库。


dependencies {   
def lifecycle_version = "1.1.1"    
// ViewModel and LiveData    
implementation "android.arch.lifecycle:extensions:$lifecycle_version"    
// alternatively - just ViewModel    
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" 
// use -ktx for Kotlin    
// alternatively - just LiveData    
implementation "android.arch.lifecycle:livedata:$lifecycle_version"    
// alternatively - Lifecycles only (no ViewModel or LiveData).   
 //     Support library depends on this lightweight import   
 implementation "android.arch.lifecycle:runtime:$lifecycle_version"   
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" 
// use kapt for Kotlin   
 // alternately - if using Java8, use the following instead of compiler  
 implementation "android.arch.lifecycle:common-java8:$lifecycle_version"    
// optional - ReactiveStreams support for LiveData   
 implementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"   
 // optional - Test helpers for LiveData   
 testImplementation "android.arch.core:core-testing:$lifecycle_version"
}

这样看起来比较麻烦吧,如果你仅仅是需要 LifecycleLiveDataViewModel只需要这样进行依赖。

dependencies {
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:extensions:$lifecycle_version" 
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
}

当然这么强大的库,肯定是支持kotlin的,kotlin的引用只需要在版本号之前加上-ktx,如下:

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

在Android框架中定义的大多数应用程序组件都有生命周期。生命周期是由操作系统或运行在你的进程中的框架代为管理的。它们是Android工作的核心,你的应用程序必须遵循它们。不这样做可能触发内存泄漏或甚至应用崩溃。
假如现在我们有一个需求,需要在屏幕上显示你的位置。一个常见的实现方式可能如下:

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }
    void start() {
        // connect to system location service
    }
    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;
    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -{
            // update UI
        });
    }
    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }
    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

尽管这个示例看起来不错,但是在真正的应用程序中,你最终会在activity的生命周期中有太多的调用,这些调用管理着UI的显示和其他组件。管理多个组件时会在生命周期方法中放置大量代码,例如onStart()和onStop(),这使得它们难以维护。
此外,不能保证你的需求代码在activity或fragment停止之前启动或者执行完毕。如果需要执行长时间运行的操作,例如onStart()中的某些配置检查,则尤其如此。这可能会导致onStop()方法在onStart()之前完成,从而使组件比需要的时间更长,或者出现严重错误,因为这种本来就是不符合生命周期规律的。

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // 如果activity结束了,这个方法才被调用,怎么办?
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}

生命周期包android.arch.lifecycle
提供类和接口,帮助你以更弹性更独离的方式解决这些问题。


Lifecycle

Lifecycle
是一个保存了关于组件(如activity或fragment)的生命周期状态信息的类,并允许其他对象观察该状态。
Lifecycle使用两个主要枚举来跟踪其相关组件的生命周期状态:
Event
从Lifecycle这个框架和Lifecycle类中分发的生命周期事件。这些事件映射到activity和fragment中的对应生命周期事件中。也就是当activity的生命周期被Lifecycle观察,Lifecycle中对应的生命周期能通过映射拿到activity当前的状态。
State
由Lifecycle对象跟踪的组件(activity / fragment)的当前生命周期状态。也就是我们能通过Lifecycle拿到activity/fragment当前的生命周期。


当然这张图我们不用关心,因为看起来不直观啊。我们来直接看看源码中是什么样子。

 public enum Event {
        /**
         * Constant for onCreate event of the {@link LifecycleOwner}.
         */
        ON_CREATE,
        /**
         * Constant for onStart event of the {@link LifecycleOwner}.
         */
        ON_START,
        /**
         * Constant for onResume event of the {@link LifecycleOwner}.
         */
        ON_RESUME,
        /**
         * Constant for onPause event of the {@link LifecycleOwner}.
         */
        ON_PAUSE,
        /**
         * Constant for onStop event of the {@link LifecycleOwner}.
         */
        ON_STOP,
        /**
         * Constant for onDestroy event of the {@link LifecycleOwner}.
         */
        ON_DESTROY,
        /**
         * An {@link Event Event} constant that can be used to match all events.
         */
        ON_ANY
    }

    /**
     * Lifecycle states. You can consider the states as the nodes in a graph and
     * {@link Event}s as the edges between these nodes.
     */
    @SuppressWarnings("WeakerAccess")
    public enum State {
        /**
         * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
         * any more events. For instance, for an {@link android.app.Activity}, this state is reached
         * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
         */
        DESTROYED,

        /**
         * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
         * the state when it is constructed but has not received
         * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
         */
        INITIALIZED,

        /**
         * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
         *     <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
         * </ul>
         */
        CREATED,

        /**
         * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onStart() onStart} call;
         *     <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
         * </ul>
         */
        STARTED,

        /**
         * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached after {@link android.app.Activity#onResume() onResume} is called.
         */
        RESUMED;

        /**
         * Compares if this State is greater or equal to the given {@code state}.
         *
         * @param state State to compare with
         * @return true if this State is greater or equal to the given {@code state}
         */

那我们就来看看具体的使用:
一个类可以通过向其方法添加注释来监视组件的生命周期状态。然后通过调用Lifecycle类的addObserver()方法添加观察者,如下面的示例所示:

//通过实现LifecycleObserver,我们就能在自己的类中观察其他组件的生命周期
public class StudyLifecycle implements LifecycleObserver{


    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate(){
        Logg.i("onCreate");
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart(){
        Logg.i("onStart");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume(){
        Logg.i("onResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause(){
        Logg.i("onPause");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop(){
        Logg.i("onStop");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy(){
        Logg.i("onDestroy");
    }


public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          //在这里添加我们的观察者
        getLifecycle().addObserver(new StudyLifecycle());
    }
}

通过这个例子可以发现,实际上我们拥有生命周期的组件(activity等)实际上是被作为了被观察者,而Lifecycle作为了观察者。这样通过push的方式,我们就能轻松的了解到组件的周期变化。


LifecycleOwner

LifecycleOwner是有单一方法的接口,实现它表示该类具有生命周期。它有一个方法,getLifecycle(),而且是必须由实现的。
这个接口从单独的类(如fragment和AppCompatActivity)抽象出生命周期的所有权,并允许编写与之一起工作的组件。任何自定义应用程序类都可以实现LifecycleOwner接口。

实现LifecycleObserver的组件与实现LifecycleOwner的组件无缝地工作。这样你就能看出来实际上我们这这里用的就是观察者模式,实现了LifecycleOwner接口的类作为被观察者,实现了LifecycleObserver接口的类作为观察者。

对于位置跟踪示例,我们可以使MyLocationListener类实现LifecycleObserver,然后在onCreate()方法中使用activity的Lifecycle初始化它。这允许MyLocationListener类自给自足,这意味着对生命周期状态的更改作出反应的逻辑是在MyLocationListener中完成的,而不是在activity中完成。让各个组件存储它们自己的逻辑使activity和fragment逻辑更易于管理。

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // update UI
        });
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}

这里有一个问题就是,例如当前的activity在onSaveInstanceState方法执行之后在调用其它回调,则会触发崩溃,因此我们永远不会希望调用该回调。
为了使用变得简单,生命周期类允许其他对象查询当前状态。

class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // disconnect if connected
    }
}

//源码中的解释:
 /**
         * Compares if this State is greater or equal to the given {@code state}.
         *
         * @param state State to compare with
         * @return true if this State is greater or equal to the given {@code state}
         */
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }

通过这个实现,我们的LocationListener类完全是能感知生命周期的。如果我们需要从另一个activity或fragment中使用我们的LocationListener,我们只需要初始化它。所有的设置和销毁等操作都是由类本身管理的。

实现自定义的 LifecycleOwner

这里要说的是,activity/fragment在Support Library 26.1.0以及以后的版本已经实现了LifecycleOwner接口。
如果您希望生成一个实现 LifecycleOwner
的自定义类,那么可以使用LifecycleRegistry
类,但是您需要将事件转发到该类中,如下面的示例代码所示:

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry mLifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

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

    @Override
    public void onStart() {
        super.onStart();
        mLifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

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

当你去查看activity源码时你会发现,源码也是基于这样实现的。并没有什么变化。

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

  • 保持UI控制器(activity/fragment)尽可能简单。它们不应该去直接获取数据;相反,使用ViewModel
    来获取数据,并观察LiveData
    对象以将数据的变化及时反应到UI。
  • 尝试编写数据驱动的UI,其中UI控制器的职责是在数据更改时更新UI,或者将用户操作通知到ViewModel。
  • 将数据的逻辑放在View模型类中。View模型应充当UI控制器和应用程序其余部分之间的连接器。但是要小心,ViewModel的责任不是来获取数据(例如,从一个网络)。相反,ViewModel应该调用适当的组件来获取数据,然后将结果返回到UI控制器。
    也就是说ViewModel只关心获取数据,但是不关心怎么获取的。听起来有一点绕口。打个比方,这里有很多管子,连接到一个大缸,我在一旁一直看着大缸里的水,监测水位的变化。这里的我就相当于UI及时的得到数据的变化,那么这个大缸就是ViewModel,它只关心缸里的水本身,至于水是从哪个管子里来的,不关心。那么管子就相当于另一个概念Repository,它只专注于水从哪里来,也就是数据的获取渠道。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容