【譯】Google官方推出的Android架構(gòu)組件系列文章(三)處理生命周期

系列文章導(dǎo)航

  1. 【譯】Google官方推出的Android架構(gòu)組件系列文章(一)App架構(gòu)指南
  2. 【譯】Google官方推出的Android架構(gòu)組件系列文章(二)將Architecture Components引入工程
  3. 【譯】Google官方推出的Android架構(gòu)組件系列文章(三)處理生命周期
  4. 【譯】Google官方推出的Android架構(gòu)組件系列文章(四)LiveData
  5. 【譯】Google官方推出的Android架構(gòu)組件系列文章(五)ViewModel
  6. 【譯】Google官方推出的Android架構(gòu)組件系列文章(六)Room持久化庫

原文地址:https://developer.android.com/topic/libraries/architecture/lifecycle.html

android.arch.lifecycle 包提供了類和接口允許你構(gòu)建生命周期感知(lifecycle-aware)的組件——可以基于當(dāng)前activity或fragment生命周期自動調(diào)節(jié)它們的行為的組件堂鲤。

注意:將 android.arch.lifecycle 導(dǎo)入Android工程逮光,請參見將Architecture Components引入工程

大部分定義在Android框架中的組件都包含附加到其上的生命周期。這些生命周期由操作系統(tǒng)或運(yùn)行在你的進(jìn)程中的框架代碼管理盯串。它們是Android如何工作的核心,你的應(yīng)用程序必須尊重它們。不這樣做可能會觸發(fā)內(nèi)存泄漏甚至應(yīng)用程序崩潰。

假設(shè)在屏幕上我們有一個(gè)展示設(shè)備位置的activity熏瞄。一個(gè)常見的實(shí)現(xiàn)可能像下面這樣:

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;

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

    public void onStart() {
        super.onStart();
        myLocationListener.start();
    }

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

即使這個(gè)例子看起來不錯(cuò),在一個(gè)真正的應(yīng)用中谬以,你最終會遇到太多像這樣的調(diào)用巴刻,然后onStart()onStop()方法會變得非常大。

此外蛉签,一些組件不能剛剛在onStart()中啟動胡陪。如果我們需要在啟動位置觀察之前檢查一些配置怎么辦?有可能某些情況檢查是在activity已經(jīng)停止之后才結(jié)束碍舍,這意味著myLocationListener.start()的調(diào)用是在myLocationListener.stop()調(diào)用之后柠座,基本上就會一直保持連接了。

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

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

    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start();
            }
        });
    }

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

android.arch.lifecycle包提供了類和接口片橡,幫助你以靈活和隔離的方式解決這些問題妈经。

Lifecycle

Lifecycle類保存有組件(如activity或fragment)的生命周期狀態(tài)信息,并允許其他對象觀察此狀態(tài)捧书。

Lifecycle使用兩個(gè)主要的枚舉來跟蹤其相關(guān)組件的生命周期狀態(tài)吹泡。

Event

從框架和Lifecycle類分派的生命周期事件。這些事件映射到activity和fragment的回調(diào)事件经瓷。

State

由Lifecycle對象跟蹤的組件的當(dāng)前狀態(tài)
lifecycle-states.png

將狀態(tài)視作圖的結(jié)點(diǎn)爆哑,事件看作這些結(jié)點(diǎn)之間的邊。

一個(gè)類可以通過給方法添加注解來觀察組件的生命周期舆吮。

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause() {
    }
}
aLifecycleOwner.getLifecycle().addObserver(new MyObserver());

LifecycleOwner

LifecycleOwner 是一個(gè)單一方法接口揭朝,表示該類擁有一個(gè)Lifecycle。它的唯一方法getLifecycle()必須被這個(gè)類實(shí)現(xiàn)色冀。

此類從單獨(dú)的類(比如activity和fragment)里抽象了Lifecycle的所有權(quán)潭袱,并允許編寫與兩者兼容的組件。任何自定義應(yīng)用程序類可以實(shí)現(xiàn)LifecycleOwner接口锋恬。

注意:由于Architecture Components還處于Alpha階段屯换,FragmentAppCompatActivity類不能實(shí)現(xiàn)它(因?yàn)槲覀儾荒軓囊粋€(gè)穩(wěn)定的組件中添加一個(gè)依賴,導(dǎo)致其變成不穩(wěn)定的API)与学。在Lifecycle穩(wěn)定之前彤悔,為了方便,提供了LifecycleActivityLifecycleFragment類癣防。在Lifecycle工程發(fā)布后蜗巧,支持庫的fragment和activity將會實(shí)現(xiàn)LifecycleOwner接口掌眠。到時(shí)將不推薦使用LifecycleActivityLifecycleFragment蕾盯。另請參閱在自定義activity和fragment中實(shí)現(xiàn)LifecycleOwner

對于上面的例子,我們可以讓MyLocationListener類成為LifecycleObserver级遭,然后在onCreate中使用我們的Lifecycle初始化它望拖。這允許MyLocationListener類是自足的,意味著它可以在必要的時(shí)候進(jìn)行自我清理挫鸽。

class MyActivity extends LifecycleActivity {
    private MyLocationListener myLocationListener;

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

一個(gè)常見的用例是说敏,避免在Lifecycle處于不良狀態(tài)時(shí)調(diào)用某些回調(diào)。例如丢郊,如果回調(diào)在activity狀態(tài)保存后運(yùn)行一個(gè)fragment事務(wù)盔沫,則會觸發(fā)崩潰,因此我們永遠(yuǎn)不會想要調(diào)用那個(gè)回調(diào)枫匾。

為了簡化此用例架诞,Lifecycle類允許其他對象查詢當(dāng)前狀態(tài)。

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.getState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

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

通過這個(gè)實(shí)現(xiàn)干茉,我們的LocationListener類是完全生命周期感知的了谴忧。它可以自行初始化和清理,而不受activity的管理角虫。如果我們需要從另一個(gè)Activity或Fragment使用它沾谓,我們只需要初始化它。所有的安裝和拆卸操作都由類本身管理戳鹅。

可以與Lifecycle一起使用的類被稱為生命周期感知組件均驶。鼓勵(lì)那些提供需要使用Android生命周期的類的庫提供生命周期感知組件,以便客戶端可以輕松繼承這些類枫虏,而無需在客戶端手動進(jìn)行生命周期管理辣恋。

LiveData是生命周期感知組件的示例。與ViewModel一起使用LiveData模软,可以在遵循Android生命周期的情況下伟骨,更容易使用數(shù)據(jù)填充UI。

Lifecycle最佳實(shí)踐

  • 保持UI控制器(activity和fragment)盡可能瘦燃异。它們不應(yīng)該視圖獲取自己的數(shù)據(jù)携狭,而是使用ViewModel來做,并觀察LiveData以將更改反映到View中回俐。
  • 嘗試別寫數(shù)據(jù)驅(qū)動的UI逛腿,你的UI控制器負(fù)責(zé)在數(shù)據(jù)更改時(shí)更新View,而不是將用戶操作通知回ViewModel仅颇。
  • 把你的數(shù)據(jù)邏輯放到ViewModel類中单默。ViewModel應(yīng)該扮演你的UI控制器和應(yīng)用其余部分之間的連接器。但是請注意忘瓦,不是ViewModel的責(zé)任來拉取數(shù)據(jù)(比如搁廓,從網(wǎng)絡(luò))。相反,ViewModel應(yīng)該調(diào)用相應(yīng)的組件來做這個(gè)事兒境蜕,然后把結(jié)果返回給UI控制器蝙场。
  • 使用Data Binding來保持view和UI控制器之間干凈的接口。這可以讓你的視圖更具聲明性粱年,并最大限度減少你需要在activity和fragment之間編寫的更新代碼售滤。如果你更喜歡Java中這么做,使用像ButterKnife這樣的庫來避免模板代碼台诗,并進(jìn)行更好的抽象完箩。
  • 如果你的UI很復(fù)雜,考慮創(chuàng)建一個(gè)Presenter類來處理UI修改拉队。這通常是過度的嗜憔,但可能讓你的UI更容易測試。
  • 永遠(yuǎn)不要在ViewModel中引用viewactivity context氏仗。如果ViewModel的生命周期超過activity(比如更改配置的情況)吉捶,activity將會泄漏,無法正確地被垃圾回收皆尔。

附錄

自定義的activity和fragment實(shí)現(xiàn)LifecycleOwer

任何自定義的activity和fragment可以通過實(shí)現(xiàn)內(nèi)置的LifecycleRegistryOwner接口(而不是擴(kuò)展LifecycleFragmentLifecycleActivity)來轉(zhuǎn)換成LifecycleOwner

public class MyFragment extends Fragment implements LifecycleRegistryOwner {
    LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}

如果你想把一個(gè)自定義類轉(zhuǎn)換成LifecycleOwner呐舔,你可以使用LifecycleRegistry類,但是你需要把事件轉(zhuǎn)發(fā)給這個(gè)類慷蠕。對于實(shí)現(xiàn)了LifecycleRegistryOwner的activity和fragment來說珊拼,轉(zhuǎn)換將會自動完成。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末流炕,一起剝皮案震驚了整個(gè)濱河市澎现,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌每辟,老刑警劉巖剑辫,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異渠欺,居然都是意外死亡妹蔽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門挠将,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胳岂,“玉大人,你說我怎么就攤上這事舔稀∪榉幔” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵内贮,是天一觀的道長产园。 經(jīng)常有香客問我汞斧,道長,這世上最難降的妖魔是什么淆两? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮拂酣,結(jié)果婚禮上秋冰,老公的妹妹穿的比我還像新娘。我一直安慰自己婶熬,他們只是感情好剑勾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赵颅,像睡著了一般虽另。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饺谬,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天捂刺,我揣著相機(jī)與錄音,去河邊找鬼募寨。 笑死族展,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拔鹰。 我是一名探鬼主播仪缸,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼列肢!你這毒婦竟也來了恰画?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤瓷马,失蹤者是張志新(化名)和其女友劉穎拴还,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欧聘,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡自沧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了树瞭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拇厢。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖晒喷,靈堂內(nèi)的尸體忽然破棺而出孝偎,到底是詐尸還是另有隱情,我是刑警寧澤凉敲,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布衣盾,位于F島的核電站寺旺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏势决。R本人自食惡果不足惜阻塑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望果复。 院中可真熱鬧陈莽,春花似錦、人聲如沸虽抄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迈窟。三九已至私植,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間车酣,已是汗流浹背曲稼。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留湖员,地道東北人躯肌。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像破衔,于是被迫代替她去往敵國和親清女。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容