Android Jetpack框架之LiveData與ViewModel分析與使用
1、前言
Google 為了幫助 Android 開發者更快更好地開發 App,推出了一系列組件,這些組件被打包成了一個整體,稱作 Android Jetpack,它包含的組件如下圖所示
官方對應 Architecture 的說明:
Android architecture components are a collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.
Manage your app's lifecycle with ease. New lifecycle-aware components help you manage your activity and fragment lifecycles. Survive configuration changes, avoid memory leaks and easily load data into your UI.
Use LiveData to build data objects that notify views when the underlying database changes.
ViewModel Stores UI-related data that isn't destroyed on app rotations.
Room is an a SQLite object mapping library. Use it to Avoid boilerplate code and easily convert SQLite table data to Java objects. Room provides compile time checks of SQLite statements and can return RxJava, Flowable and LiveData observables.
翻譯:
Android體系結構組件是一組庫,可幫助您設計健壯,可測試和可維護的應用程序。 從用于管理UI組件生命周期和處理數據持久性的類開始。
輕松管理應用程序的生命周期。 新的生命周期感知組件可幫助您管理活動和碎片生命周期。 生存配置更改,避免內存泄漏并輕松將數據加載到UI中。
使用LiveData構建數據對象,以便在基礎數據庫更改時通知視圖。
ViewModel存儲在應用程序輪換中未銷毀的UI相關數據。
Room是一個SQLite對象映射庫。 使用它來避免樣板代碼并輕松地將SQLite表數據轉換為Java對象。 Room提供SQLite語句的編譯時檢查,可以返回RxJava,Flowable和LiveData observable。
官方推薦的應用架構指南
常見架構原則
1.分離關注點
要遵循的最重要的原則是分離關注點一種常見的錯誤是在一個 Activity 或 Fragment中編寫所有代碼。這些基于界面的類應僅包含處理界面和操作系統交互的邏輯。應盡可能使這些類保持精簡,這樣可以避免許多與生命周期相關的問題。
請注意,您并不擁有 Activity 和 Fragment的實現,這些只是表示 Android 操作系統與應用之間關系的粘合類。操作系統可能會根據用戶交互或因內存不足等系統條件隨時銷毀它們。為了提供令人滿意的用戶體驗和更易于管理的應用維護體驗,最好盡量減少對它們的依賴。
2.用過模型驅動界面
另一個重要原則是您應該通過模型驅動界面,最好是持久性模型。模型是負責處理應用數據的組件。它們獨立于應用中的 View 對象和應用組件,因此不受應用的生命周期以及相關關注點的影響。
持久性是理想之選,原因如下
- 如果 Android 操作系統銷毀應用以釋放資源,用戶不會丟失數據。
- 當網絡連接不穩定或不可用時,應用會繼續工作。
應用所基于的模型類應明確定義數據管理職責,這樣將使應用更可測試且更一致。
看下圖,該圖顯示了設計應用后所有模塊應如何交互
請注意,每個組件僅依賴于其下一級的組件。例如,Activity 和 Fragment 僅依賴于視圖模型。存儲區是唯一一個依賴于其他多個類的類;在本例中,存儲區依賴于持久性數據模型和遠程后端數據源。
這種設計打造了一致且愉快的用戶體驗。無論用戶是在上次關閉應用幾分鐘后還是幾天后回到應用,他們都會立即看到應用在本地保留的用戶信息。如果此數據已過時,則應用的存儲區模塊將開始在后臺更新數據。
2、介紹LiveData與ViewModel
ViewModel類旨在以生命周期意識的方式存儲和管理與UI相關的數據。 ViewModel類允許數據在配置更改(例如屏幕旋轉)后繼續存在。
示例代碼
public class FlowerModel extends ViewModel {
private MutableLiveData<Data> liveData;
public MutableLiveData<Data> getLiveData() {
if (liveData == null){
liveData = new MutableLiveData<>();
}
return liveData;
}
public static class Data {
public int send;
public int less;
public List<PaintView.DrawPath> list;
}
}
flowerModel = ViewModelProviders.of(getActivity()).get(FlowerModel.class);
然后利用LiveData通知界面更新UI
LiveData 是一種可觀察的數據存儲器。應用中的其他組件可以使用此存儲器來監控對象的更改,而無需在它們之間創建明確且嚴格的依賴路徑。LiveData 組件還遵循應用組件(如 Activity、Fragment 和 Service)的生命周期狀態,并包括清理邏輯以防止對象泄漏和過多的內存消耗。
flowerModel.getLiveData().observe(getActivity(), new Observer<FlowerModel.Data>() {
@Override
public void onChanged(@Nullable FlowerModel.Data data) {
//update UI
}
});
Demo演示
3、項目中應用
4、淺析原理與使用
ViewModel生命周期
- ViewModel對象的范圍是在獲取ViewModel時傳遞給ViewModelProvider的Lifecycle生命周期-
- ViewModel在內存中直到Activity銷毀或Fragment被移除
- 系統首次調用活動對象的onCreate()方法時,通常會請求ViewModel
- 系統可能會在整個活動的整個生命周期中多次調用onCreate(),例如當設備屏幕旋轉時
- ViewModel從第一次請求ViewModel直到活動完成并銷毀時存在
ViewModel生命周期圖
看源碼
1,獲取ViewModelProvider
ViewModelProviders提供四個構造方法創建VIewProvider,兩個帶有factory兩個沒有,不過沒有factory的其實使用的是默認的Factory,所以四個方法基本一致只是Fragment和Activity的區分
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
獲取ViewModelStore:由前面的源碼可以知道創建ViewProvider時傳入兩個參數:ViewModelStore 和 Factory;顯然從名字就可以看出他們的作用,Factory負責創建,ViewModelStore負責存儲
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
上面的執行是,先去ViewModelStore中獲取,如果為空就調用Factory的create()創建ViewModel,并儲存在VIewmoStore中
ViewModelProviders.of(SquareFragment.this).get(AudioLiveData.class)的執行流程大概圖 忽略創建和存儲細節
2,通過ViewModelStores.of(this)創建ViewModelStore 源碼
private ViewModelStores() {
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
先判斷Activity是否為 ViewModelStoreOwner,如果是直接獲取其中的ViewModelStore,否則調用holderFragmentFor(activity).getViewModelStore()獲取
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
...
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
//通過manager.findFragmentByTag(HOLDER_TAG)找到fragment
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
//在map中取
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
//創建 HolderFragment
holder = createHolderFragment(fm);
//存到map中
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
其中 findHolderFragment
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
throw new IllegalStateException("Unexpected "
+ "fragment instance was returned by HOLDER_TAG");
}
return (HolderFragment) fragmentByTag;
}
map中get
@SuppressWarnings("WeakerAccess")
static class HolderFragmentManager {
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
...
holder = mNotCommittedActivityHolders.get(activity);
createHolderFragment
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
3, HolderFragment存儲ViewModelStore
上面都是獲取或者創建HolderFragment的過程,有沒有想過我們存儲ViewModel的地方,為什么一直在操作fragment ?我們回頭看創建ViewModelStore的地方
有這么個判斷 activity instanceof ViewModelStoreOwner
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
...
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
而HolderFragment實現了ViewModelStoreOwner,同時保存了ViewModelStore
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class HolderFragment extends Fragment implements ViewModelStoreOwner {
...
private ViewModelStore mViewModelStore = new ViewModelStore();
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
ViwModelStore 利用HashMap獲取,存儲 ViewModel
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
獲取ViewModelStore的整體執行流程
總結一下ViewModel內部的存儲邏輯
- 根據傳入的Activity/Fragment獲取、創建、添加并以activity為鍵保存Fragment(因此在屏幕發生旋轉時生命周期改變兩次創建activity時獲取的都是同一個fragment因為key相同)
- 獲取Fragment中保存的ViewModelStore對象(ViewModelStore中使用Map儲存ViewModel)
- 創建ViewModelProvider實例,ViewModelProvider中封裝了獲取的ViewModelStore和創建用的Factory
- 從VIewModelStore的Map中或Factory的create()中獲取ViewModel
LiveData 是一個觀察者模型,但是它是一個與 Lifecycle 綁定了的 Subject,也就是說,只有當 UI 組件處于 ACTIVE 狀態時,它的 Observer 才能收到消息,否則會自動切斷訂閱關系
- LiveData 只要有數據更新,它的 observer 就會收到通知。如果我們要把 LiveData 用作事件總線(類似EventBus),還需要做一些定制,可以使用google官方demo里的 SingleLiveEvent 。
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
@MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
@MainThread
public void setValue(@Nullable T t) {
mPending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
public void call() {
setValue(null);
}
}
- 我們沒法直接修改 LiveData 的 value,因為它是不可變的(immutable),可變(mutable)版本是 MutableLiveData,通過調用 setValue(主線程)或 postValue(非主線程)可以修改它的 value
- LiveData 有一個實現了中介者模式的子類 —— MediatorLiveData,它可以把多個 LiveData 整合成一個,只要任何一個 LiveData 有數據變化,它的觀察者就會收到消息
匯總一下 LiveData 的使用場景:
* LiveData - immutable 版本*
* MutableLiveData - mutable 版本
* MediatorLiveData - 可匯總多個數據源
* SingleLiveEvent - 事件總線
- Transformations.map 對存儲在LiveData對象中的值修改,并將結果發送到下游
private class User{
private User(String id){ this.userId = id; }
private String userName;
private String userId;
}
private MutableLiveData<User> userMutableLiveData;
public void test(){
userMutableLiveData = new MutableLiveData<>();
LiveData<String> userName = Transformations.map(userMutableLiveData, new Function<User, String>() {
@Override
public String apply(User input) {
return "姓名"+input.userName;
}
});
- Transformations.switchMap 動態返回LiveData
private class User{
private User(String id){ this.userId = id; }
private String userName;
private String userId;
}
private MutableLiveData<User> userMutableLiveData;
public void test(){
userMutableLiveData = new MutableLiveData<>();
LiveData<String> userId = new MutableLiveData<>();
LiveData<User> user2 = Transformations.switchMap(userId, new Function<String, LiveData<User>>() {
@Override
public LiveData<User> apply(String input) {
return getUser(input);
}
});
}
private LiveData<User> getUser(String id){
User user = new User(id);
userMutableLiveData.setValue(user);
return userMutableLiveData;
}
MutableLiveData只是LiveData的一個擴展類,重寫了LiveData中的protected方法postValue()和setValue(),調用了super.postValue()和super.setValue(),也就是說所有的方法都是在LiveData中實現
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
先看 observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
flowerModel.getLiveData().observe(getActivity(), new Observer<FlowerModel.Data>() {
@Override
public void onChanged(@Nullable FlowerModel.Data data) {
//update UI
}
});
...
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// 如果已經銷毀就返回
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
- 在observe中首先判斷了當前Lifecycler的狀態,當Destroy時即觀察者不處于活躍狀態,不用接收數據
- 創建LifecycleBoundObserver實例保存傳入的LifecycleOwner和Observer,并保存在mObservers
- 添加LifecycleOwner的觀察者,響應生命周期的變化
繼續看 LifecycleBoundObserver
private abstract class ObserverWrapper {
final Observer<T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<T> observer) {
//保存觀察者Observer
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state,
//so we'd never dispatch anything to inactive owner
//立即設置活動狀態,因此我們永遠不會向非活動所有者發送任何內容
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();// 當Activity/Fragment為活躍狀態時回調onActive()
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive(); // 當Activity/Fragment未活躍狀態時回調onInactive()
}
if (mActive) {
dispatchingValue(this);
}
}
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);// 調用父類ObserverWrapper的構造函數傳遞Owner
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 實現GenericLifecycleObserver 當生命周期改變時回調onStateChanged
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);// DESTROYED時移除觀察者
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
- ObserverWrapper 在Owner活躍狀態改變時回調onActive和onInactive方法
- LifecycleBoundObserver主要利用Lifecycler的生命周期觀察者GenericLifecycleObserver,當設置了owner.getLifecycle().addObserver(wrapper)后,當生命周期改變時會回調onStateChange()方法,在生命周期為Destroy時移除Observer
setValue(T value) (主線程)
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");//檢測是否在主線程
mVersion++;
mData = value;
dispatchingValue(null);
}
...
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
//遍歷mObservers中所有的Observer,調用considerNotify()更新數據
for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
...
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//更新數據 通過接口回調
observer.mObserver.onChanged((T) mData);
}
...
public interface Observer<T> {
void onChanged(@Nullable T t);
}
...
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class DefaultTaskExecutor extends TaskExecutor {
private final Object mLock = new Object();
private ExecutorService mDiskIO = Executors.newFixedThreadPool(2);
@Nullable
private volatile Handler mMainHandler;
@Override
public void executeOnDiskIO(Runnable runnable) {
mDiskIO.execute(runnable);
}
@Override
public void postToMainThread(Runnable runnable) {
//子線程向主線程發消息
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = new Handler(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
@Override
public boolean isMainThread() {//檢測是否在主線程具體實現
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
- setValue()中先檢查是否主線程然后調用了dispatchingValue(),在dispatchingValue中遍歷mObservers中所有的Observer,調用considerNotify()中.mObserver.onChanged(T)更新數據
postValue(T value)(子線程)
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
...
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
- postValue()中傳遞的Runnable 也是調用setValue() 只不過是通過handle在子線程向主線程發消息
5.展望
本次分享只是分析了ViewModel,LiveData 的大概源碼,與簡單示例,但其實在實際生產環境中,我們需要使用ViewModel與Repository連接網絡層,同時如果需要數據持久化還需要連接Room數據庫層,通過ViewModel生成LiveData,UI層訂閱LiveData,真正的實現數據驅動界面