Android官方架構(gòu)組件介紹之LifeCycle

Google 2017 I/O開發(fā)者大會于近日召開,在開發(fā)者大會上谷歌除了發(fā)布了Android O等一些新產(chǎn)品之外,也對Android代碼的架構(gòu)做出了一個官方的回應(yīng)。

Google 2017 I/O開發(fā)者大會Android架構(gòu)組件介紹現(xiàn)場視頻

下面是官方提供的Android App開發(fā)的架構(gòu)圖:

google官方Android架構(gòu)圖

從上圖可以看到一些關(guān)鍵字:ViewModel,LiveData,Room等。其實看了上面視頻的會發(fā)現(xiàn)Google官方Android架構(gòu)組件一共包括以下幾個:

  • LifeCycle : 與Activity和Fragment的生命周期有關(guān)
  • LiveData :異步可訂閱數(shù)據(jù),也是生命周期感知
  • ViewModel :視圖數(shù)據(jù)持有模型,也是生命周期感知
  • Room :SQLite抽象層,用于簡化SQLite數(shù)據(jù)存儲

這篇文章主要講解LifeCycle在項目的簡單用法。

AS中添加依賴

首先在工程根目錄的build.gradle中添加一下內(nèi)容:

allprojects {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }  //添加此行
    }
}

然后在應(yīng)用目錄下的build.gradle中添加以下依賴:

//For Lifecycles, LiveData, and ViewModel
compile "android.arch.lifecycle:runtime:1.0.0-alpha1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"

//For Room
compile "android.arch.persistence.room:runtime:1.0.0-alpha1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"

LifeCycle相關(guān)使用

在我們平時的項目中經(jīng)常會遇到很多需要依賴生命周期的邏輯處理,比如有這么一個需求。
在某個Activity我們需要在屏幕上展現(xiàn)用戶的地理位置。簡單的實現(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();
    }
}

雖然以上代碼看起來很簡潔,但在實際項目中的onStart,onStop方法可能會變得相當(dāng)龐大。
此外,實際情況可能并不像上面這么簡單,例如我們需要在start位置監(jiān)聽前做用戶狀態(tài)檢測,檢測是一個耗時的任務(wù),那么很有可能在檢測結(jié)束前用戶提前退出了Activity,這時候就會導(dǎo)致myLocationListener.start()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();
    }
}

這時候就該今天的主角LifeCycle出場了。它提供了一套接口幫助你處理這些問題。

LifeCycle

LifeCyle類持有Activity或者Fragment的生命周期相關(guān)信息,并且支持其他對象監(jiān)聽這些狀態(tài)。

LifeCyle有兩個枚舉用于追蹤生命周期中的狀態(tài)。

Event

這是生命周期的事件類,會在Framework和LifeCycle間傳遞,這些事件映射到Activity和Fragment的回調(diào)事件中。

State

LifeCycle所持有Activity或Fragment的當(dāng)前狀態(tài)。

一個類想要監(jiān)聽LifeCycle的狀態(tài),只需要給其方法加上注解:

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是一個只有一個方法的接口用于表明其有一個LifeCycle對象。這個方法為getLifecycle()
這個對象給Acitivity,F(xiàn)ragment和LifeCycle提供了一個很好的抽象關(guān)系,Activity和Fragment只要實現(xiàn)這個接口就能配合LifeCycle實現(xiàn)生命周期監(jiān)聽。

注意:由于目前LifeCycle處于alpha階段,所以Fragment和AppCompatActivity并不會實現(xiàn)這些方法,在此之前,可以使用LifecycleActivityLifecycleFragment。等LifeCycle趨于穩(wěn)定后,F(xiàn)ragment和AppCompatActivity會默認(rèn)實現(xiàn)這些。

對于之前的位置監(jiān)聽的例子,我們可以讓MyLocationListener繼承LifecycleObserver,在onCreate中使用LifeCycle進(jìn)行初始化,剩下的問題則不必?fù)?dān)心了。因為MyLocationListener有能力進(jìn)行生命周期的判斷。

class MyActivity extends LifecycleActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        //此處進(jìn)行初始化getLifecycle()傳入LifeCycle對象
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // update UI
        });
        //檢測用戶狀態(tài)并啟用監(jiān)聽
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}

下面看一下MyLocationListener

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

LifeCycle最重要的特性就是在?處,他可以提供主動查詢生命周期狀態(tài)的方法。這樣就避免了上面遇到的myLocationListener.start()myLocationListener.stop()后面調(diào)用的問題。

通過以上的實現(xiàn),我們的LocationListener是完全的生命周期感知了,它可以進(jìn)行自己的初始化和資源清理而不必受Activity或者Fragment的管理。這時候如果我們在其他Activity或者Fragment中使用LocationListener,我們只需要初始化它就行了,不必再擔(dān)心生命周期對它的影響,因為它內(nèi)部會做好這一切。

通過LefeCycle工作的類我們稱之為生命周期感知。鼓勵需要使用Android生命周期的類的庫提供生命周期感知組件,以便客戶端可以輕松地在客戶端上集成這些類,而無需手動生命周期管理。

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

生命周期的最佳實踐

  • 保持你的UI(Activity和Fragment)盡可能簡潔。它們不應(yīng)該試圖獲取它們的數(shù)據(jù)而是使用ViewModel來執(zhí)行此操作,并通過LiveData的回調(diào)將數(shù)據(jù)更新到UI中。
  • 嘗試編寫數(shù)據(jù)驅(qū)動的UI,你的UI的責(zé)任是在數(shù)據(jù)更改時更新視圖,或?qū)⒂脩舨僮魍ㄖoViewModel。
  • 將你的數(shù)據(jù)邏輯放在ViewModel類中。 ViewModel應(yīng)該作為UI和其他數(shù)據(jù)操作的連接器。值得注意的是,ViewModel并不負(fù)責(zé)提取數(shù)據(jù)(例如,從網(wǎng)絡(luò))。相反,ViewModel應(yīng)該調(diào)用其他接口來執(zhí)行此工作,然后將結(jié)果提供給UI。
  • 使用Data Binding可以讓你的的UI代碼變得相當(dāng)干凈利落。這將使你的UI更具聲明性,并最大限度地減少書寫UI更新的代碼。如果您更喜歡在Java中執(zhí)行此操作,請使用像Butter Knife這樣的庫來避免使用樣板代碼并進(jìn)行更好的抽象。
  • 如果你有一個復(fù)雜的UI,請考慮創(chuàng)建一個Presenter類來處理UI修改。這通常是過度架構(gòu)的,但可能有助于使你的UI更容易測試。
  • 不要在ViewModel中引用View或Activity上下文。如果ViewModel在Activity或View銷毀的情況下依舊存活,這時將導(dǎo)致內(nèi)存泄漏。

補充

在自定義的Activity或Fragment中實現(xiàn)LifeCycleOwner,可以實現(xiàn)LifecycleRegistryOwner這個接口。而不是繼承(LifeCycleFragment和LifeCycleActivity)

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

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

如果你要在自定義的類中實現(xiàn)LifeCycleOwner,可以使用LifecycleRegistry,但是你需要主動向其轉(zhuǎn)發(fā)生命周期的事件。但如果你自定義類是Fragment和Activity的話并且它們實現(xiàn)的是LifecycleRegistryOwner,那么事件轉(zhuǎn)發(fā)都是自動完成的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,643評論 2 380

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