Android Jetpack 架構組件
架構原則
關注分離點
要遵循的最重要的原則是分離關注點。一種常見的錯誤是在一個 Activity 或 Fragment 中編寫所有代碼。這些基于界面的類應僅包含處理界面和操作系統交互的邏輯。應盡可能使這些類保持精簡,這樣可以避免許多與生命周期相關的問題。
請注意,您并不擁有 Activity 和 Fragment 的實現,這些只是表示 Android 操作系統與應用之間關系的粘合類。操作系統可能會根據用戶交互或因內存不足等系統條件隨時銷毀它們。為了提供令人滿意的用戶體驗和更易于管理的應用維護體驗,最好盡量減少對它們的依賴。
通過模型驅動界面
另一個重要原則是您應該通過模型驅動界面,最好是持久性模型。模型是負責處理應用數據的組件。它們獨立于應用中的 View 對象和應用組件,因此不受應用的生命周期以及相關關注點的影響。
持久性是理想之選,原因如下:
- 如果 Android 操作系統銷毀應用以釋放資源,用戶不會丟失數據。
- 當網絡連接不穩定或不可用時,應用會繼續工作。
應用所基于的模型類應明確定義數據管理職責,這樣將使應用更可測試且更一致。
以上內容在摘自Google官方文檔:應用架構指南
本文主要內容
Lifecycle : 管理您的 Activity 和 Fragment 生命周期
ViewModel : 以注重生命周期的方式管理界面相關的數據
LiveData : 在底層數據更改時通知視圖
Lifecycle
生命周期管理(Lifecycles)組件,幫助開發者創建 “可感知生命周期的” 組件,讓其自己管理自己的生命周期,從而減少內存泄露和崩潰的可能性。
android.arch.lifecycle組件提供一系列接口讓開發者很容易自定義可監聽生命周期的組件——根據生命周期組件的狀態改變自定義組件的行為!
相關類簡介
- Lifecycle
抽象Android組件(Activity/Fragment)的生命周期,可通過addObserver(LifecycleObserver observer)監聽其狀態
- LifecycleObserver
抽象生命周期觀察者接口,內部無抽象方法,實際通過注解方法的方式接收生命周期變更事件
- LifecycleOwner
持有生命周期對象,包含抽象方法Lifecycle getLifecycle()
- LifecycleRegistry
Lifecycle具體實現類
- ReportFragment
Activity生命周期變更時通過attach一個ReportFragment接收生命周期回調方法,然后在ReportFragment中調用LifecycleRegistry.handleLifecycleEvent(event),最終把事件傳遞給觀察Lifecycle的LifecycleObserver對象
自定義LifecycleObserver
繼承LifecycleObserver,通過注解自定義方法接收生命周期變更事件
注意這種方式被注解的方法最多可以有兩個參數,并且需準守以下規則:
- 空參數 ()
- 一個參數(LifecycleOwer ower)
- 兩個參數(LifecycleOwer ower, Lifecycle.Event event),對應注解Lifecycle.Event.ON_ANY
例如給以下位置服務組件,添加響應生命周期組件事件
class LocationService implements LifecycleObserver{
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void start() {
// do get location
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void stop(LifecycleOwer ower) {
// do stop get location
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onAny(LifecycleOwer ower, Lifecycle.Event event) {
// do something
}
public void addListener(LocationListener listener) {
}
}
創建Lifecycle對象,監聽Lifecycle
public class MyActivity extends Activity implements LifecycleOwner {
private LifecycleRegistry lifecycleRegistry;
private LocationService locationService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
locationService = new LocationService();
getLifecycle().addObserver(locationService);
}
@Override
public void onStart() {
super.onStart();
lifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@Override
public void onResume() {
super.onResume();
lifecycleRegistry.markState(Lifecycle.State.RESUMED);
}
// ...省略其他生命周期方法...
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}
如果使用java8 則繼承DefaultLifecycleObserver,并且添加依賴
class TestObserver implements DefaultLifecycleObserver {
* Override
* public void onCreate(LifecycleOwner owner) {
* // your code
* }
* }
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
Activity生命周期對應 Lifecycle 狀態
image
ViewModel
主要特點
- 幫助UI Controller準備數據給View展示,將數據獲取從UI Controller分離出來
- 在橫豎屏切換時數據不會被銷毀
- ViewModel獨立于View和LifecycleOwner,便于測試
- 可以在不同Fragment中共享數據
ViewModel的生命周期
使用Demo
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// 在第一次調用onCreate()時創建ViewModel
// 重復調用onCreate()會獲取到第一次創建的ViewModel
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
在同一個Activity中的Fragment之間共享ViewModel
有以下好處
- 不用在Activity里協調Fragment之間的數據
- Fragment不用關心其他Fragment跟ViewModel之間的關系
- 每個Fragment都有自己的生命周期,不會受到其他Fragment的影響
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
使用ViewModle替換Loaders
主要目的在于將數據獲取從UI Controller中分離出來,讓ViewModel持有數據(Model)
LiveData
是一種可觀察的數據存儲器。應用中的其他組件可以使用此存儲器來監控對象的更改,而無需在它們之間創建明確且嚴格的依賴路徑。LiveData 組件還遵循應用組件(如 Activity、Fragment 和 Service)的生命周期狀態,并包括清理邏輯以防止對象泄漏和過多的內存消耗。
LiveData的優勢
- 典型的觀察者模式,保證UI展示跟數據同步
- 不用擔心內存泄露,LiveData會在lifecycle生命周期結束時自動清理,不用手動remove觀察者(observeForever()除外,需要手動調用removeObserver()方法移除)
- 不會因為Activity stoped而crash,LiveData會監聽Activity的狀態,在inactive狀態時不會給組件發送事件
- 不用手動管理生命周期
- 總是會刷新數據(比如Activity在后臺,這時數據更新了,當Activity回到前臺時會接收到數據更新事件)
- 橫豎屏切換時也會觸發數據更新事件
- 共享數據,你可以使用單例模式實現自己的LiveData,不同的組件可以監聽它達到數據共享的目的
使用方法
LiveData<T>是一個泛型類,通常結合ViewModel使用(ViewModel的目的是將數據和UI Controller組件分離),例如:
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<String>();
}
return currentName;
}
}
通常在onCreate方法里添加觀察者
- 不要在onResume()方法中重復添加
- 再者可以保證數據及時被顯示出來
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(this).get(NameViewModel.class);
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
}
}
在調用observe()方法之后,且LiveData有設置初始化數據,如果Activity是active狀態,onChanged方法會立刻回調,或者當Activity狀態改變為active狀態時回調
使用LiveData來更新UI的好處
- 防止Fragment或Activity過于臃腫,他們的職責是用來展示數據,但不持有數據
- 將LiveData從UI Controller中分離,這樣可以使得在configuration變更時數據不被銷毀(所以一般將LiveData放在ViewModel對象里面使用,因為ViewModel獨立于UI Controller)
更新數據
// 主線程回調
public void postValue(T value)
// 當前線程回調
public void setValue(T value)
自定義LiveData
主要重載下面三個方法:
- onActive() 當LiveData有一個觀察者處于active狀態時回調
- onInactive() 當所有觀察者處于inactive狀態時回調
- setValue(T value) 設置數據并給對應處于active狀態的觀察者發送通知
例如下面獲取地理位置信息LocationLiveData
public class LocationLiveData extends LiveData<Location> {
// 地理位置服務
private LocationService locationService = new LocationService();
public LocationLiveData() {
locationService.addListener(new LocationListener() {
public void onLocation(Location location) {
setValue(location);
}
});
}
@Override
protected void onActive() {
// 當有活躍狀態觀察者時開啟地理位置獲取
locationService.start();
}
@Override
protected void onInactive() {
// 當有沒有活躍狀態觀察者時開啟地理位置獲取
locationService.stop();
}
}
LiveData變換
public static <X, Y> LiveData<Y> map(LiveData<X> source, final Function<X, Y> mapFunction)
public static <X, Y> LiveData<Y> switchMap(LiveData<X> source, final Function<X, LiveData<Y>> switchMapFunction)
兩個方法差不多,只是map轉換函數返回具體數據對象,switchMap返回LiveData<T>
- User --> userName
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
- userId --> User
private LiveData<User> getUser(String id) {
...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
Lifecycle 和 LiveData 的區別
Lifecycle和LiveData都類似觀察者模式
- Lifecycle具有生命周期的概念,而LiveData沒有生命周期,他是根據觀察者(LifecycleOwner)的生命周期狀態來決定要不要回調Observer.onChange()方法
- Lifecycle添加觀察者是LifecycleObserver,他是一個空接口,實際回調是LifecycleObserver實現類的注解方法
- LiveData會根據LifecycleOwner的生命周期為ON_DESTROY時自動移除Observer