使用生命周期感知型組件處理生命周期
編寫說明,文章收錄于《Android Jetpack》,文章將大部分摘錄于
[官方教程]https://developer.android.google.cn/topic/libraries/architecture/lifecycle
1.核心功能
生命周期感知型組件可執行操作來響應另一個組件(如 Activity 和 Fragment)的生命周期狀態的變化。這些組件有助于您寫出更有條理且往往更精簡的代碼,這樣的代碼更易于維護。
一種常見的模式是在 Activity 和 Fragment 的生命周期方法中實現依賴組件的操作。但是,這種模式會導致代碼條理性很差而且會擴散錯誤。通過使用生命周期感知型組件,您可以將依賴組件的代碼從生命周期方法移入組件本身中。
androidx.lifecycle
軟件包提供了可用于構建生命周期感知型組件的類和接口 - 這些組件可以根據 Activity 或 Fragment 的當前生命周期狀態自動調整其行為。
以下以定位代碼為例:
1.以往的方式
常見的模式是在 Activity 和 Fragment 的生命周期方法中實現依賴組件的操作。
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
}
}
2.使用生命周期感知型組件
MyLocationListener.java
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
}
}
MyActivity.java
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();
}
});
}
}
1、2是使用Lifecycle改造常規涉及Android組件(Activity)生命業務代碼的既簡單,又清晰的例子,至于部分代碼的含義,會在后續中做一些說明。
2.生命周期
Lifecycle
是一個類,用于存儲有關組件(如 Activity 或 Fragment)的生命周期狀態的信息,并允許其他對象觀察此狀態。
Lifecycle
使用兩種主要枚舉跟蹤其關聯組件的生命周期狀態:
事件
從框架和 Lifecycle
類分派的生命周期事件。這些事件映射到 Activity 和 Fragment 中的回調事件。
狀態
由 Lifecycle
對象跟蹤的組件的當前狀態。
您可以將狀態看作圖中的節點,將事件看作這些節點之間的邊。
類可以通過向其方法添加注解來監控組件的生命周期狀態。然后,您可以通過調用 Lifecycle
類的 addObserver()
方法并傳遞觀察者的實例來添加觀察者,如以下示例中所示:
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
...
}
}
myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
3、LifecycleOwner
LifecycleOwner
是單一方法接口,表示類具有 Lifecycle
。它具有一種方法(即 getLifecycle()
),該方法必須由類實現。如果您嘗試管理整個應用進程的生命周期,請參閱 ProcessLifecycleOwner
。
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.lifecycle;
import androidx.annotation.NonNull;
/**
* A class that has an Android lifecycle. These events can be used by custom components to
* handle lifecycle changes without implementing any code inside the Activity or the Fragment.
*
* @see Lifecycle
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
@NonNull
Lifecycle getLifecycle();
}
此接口從各個類(如 [Fragment](https://developer.android.google.cn/reference/androidx/fragment/app/Fragment)
和 [AppCompatActivity](https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatActivity)
)抽象化 Lifecycle
的所有權,并允許編寫與這些類搭配使用的組件。任何自定義應用類均可實現 LifecycleOwner
接口。
實現 LifecycleObserver
的組件可與實現 LifecycleOwner
的組件無縫協同工作,因為所有者可以提供生命周期,而觀察者可以注冊以觀察生命周期。
對于位置跟蹤示例,我們可以讓 MyLocationListener
類實現 LifecycleObserver
,然后在 [onCreate()](https://developer.android.google.cn/reference/android/app/Activity#onCreate(android.os.Bundle))
方法中使用 Activity 的 Lifecycle
對其進行初始化。這樣,MyLocationListener
類便可以“自給自足”,這意味著,對生命周期狀態的變化做出響應的邏輯會在 MyLocationListener
(而不是在 Activity)中進行聲明。讓各個組件存儲自己的邏輯,可使 Activity 和 Fragment 邏輯更易于管理。
以上就對位置跟蹤的示例做了一個說明
4.生命周期感知型組件的最佳做法
- 使界面控制器(Activity 和 Fragment)盡可能保持精簡。它們不應試圖獲取自己的數據,而應使用
ViewModel
執行此操作,并觀察LiveData
對象以將更改體現到視圖中。 - 設法編寫數據驅動型界面,對于此類界面,界面控制器的責任是隨著數據更改而更新視圖,或者將用戶操作通知給
ViewModel
。 - 將數據邏輯放在
ViewModel
類中。ViewModel
應充當界面控制器與應用其余部分之間的連接器。不過要注意,ViewModel
不負責獲取數據(例如,從網絡獲取)。ViewModel
應調用相應的組件來獲取數據,然后將結果提供給界面控制器。 - 使用 Data Binding 在視圖與界面控制器之間維持干凈的接口。這樣一來,您可以使視圖更具聲明性,并盡量減少需要在 Activity 和 Fragment 中編寫的更新代碼。如果您更愿意使用 Java 編程語言執行此操作,請使用諸如 Butter Knife 之類的庫,以避免樣板代碼并實現更好的抽象化。
- 如果界面很復雜,不妨考慮創建 presenter 類來處理界面的修改。這可能是一項艱巨的任務,但這樣做可使界面組件更易于測試。
- 避免在
ViewModel
中引用[View](https://developer.android.google.cn/reference/android/view/View)
或[Activity](https://developer.android.google.cn/reference/android/app/Activity)
上下文。如果ViewModel
存在的時間比 Activity 更長(在配置更改的情況下),Activity 將泄露并且不會由垃圾回收器妥善處置。 - 使用 Kotlin 協程管理長時間運行的任務和其他可以異步運行的操作。
5、生命周期感知型組件的用例
- 在粗粒度和細粒度位置更新之間切換。使用生命周期感知型組件可在位置應用可見時啟用細粒度位置更新,并在應用位于后臺時切換到粗粒度更新。借助生命周期感知型組件
LiveData
,應用可以在用戶使用位置發生變化時自動更新界面。 - 停止和開始視頻緩沖。使用生命周期感知型組件可盡快開始視頻緩沖,但會推遲播放,直到應用完全啟動。此外,應用銷毀后,您還可以使用生命周期感知型組件終止緩沖。
- 開始和停止網絡連接。借助生命周期感知型組件,可在應用位于前臺時啟用網絡數據的實時更新(流式傳輸),并在應用進入后臺時自動暫停。
- 暫停和恢復動畫可繪制資源。借助生命周期感知型組件,可在應用位于后臺時暫停動畫可繪制資源,并在應用位于前臺后恢復可繪制資源。