這幾個庫理論上應該都會使用, 我認爲屬於JetPack中的基礎庫, 早期稱爲ArchitectureComponent, 後被併入Jetpack組件庫之中.php
androidx內置LiveData/ViewModel/Lifecycle, 無需導入依賴.html
LiveData: 感知活躍(onStart)和非活躍狀態(onPause)的數據觀察者java
ViewModel: 屏幕旋轉自動保存數據, 或者意外銷燬讀寫saveInstance數據android
Lifecyle: 能夠監聽生命週期, 默認Activity和Fragment已經實現lifecyclegit
參考文獻github
ViewModel只能在屏幕旋轉時保存數據, 而沒法在內存回收Activity時保存數據(除非使用SavedState)框架
ViewModel
用於繼承實現自定義的數據實體
ViewModelStore
存儲多個ViewModel的存儲類, 開發者無需關心
ViewModelStoreOwner
Fragment|Activity都屬於其派生類. 在ViewModelProvider建立時使用.
ViewModelProvider
用於建立ViewModel
建立ViewModule
public class LiveDataTimerViewModel extends ViewModel {
/**/ } 複製代碼
使用
綁定生命週期同時返回一個ViewModel實例
ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory(application)).get(T::class.java) 複製代碼
ViewModel有個覆寫函數, 用於提供依附的ViewModelStoreOwner銷燬是清理數據(設置對象爲NULL/解綁監聽器等)
protected void onCleared ()
複製代碼
默認的AppCompatActivity
就實現了LifeCycleOwner
和ViewModelStoreOwner
public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner, OnBackPressedDispatcherOwner {
//...
}
複製代碼
同時Fragment
也實現了ViewModelStoreOwner
ViewModel綁定生命週期的對象必須實現ViewModelStoreOwner
. 該接口的職責是保存ViewModelStore對象.
咱們能夠經過實現該接口自定義
public interface ViewModelStoreOwner {
/** * Returns owned {@link ViewModelStore} * * @return a {@code ViewModelStore} */
@NonNull
ViewModelStore getViewModelStore();
}
複製代碼
ViewModelStore
能夠看作一個HashMap集合存儲ViewModel的類, 能夠建立對象
public final void clear() // 會觸發全部ViewModel對象的onClear函數. 該函數中通常用於ViewModel是否某些內存 複製代碼
ViewModel必須經過該類建立對象
val model = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get<Model>()
複製代碼
構造函數
public ViewModelProvider (ViewModelStoreOwner owner, ViewModelProvider.Factory factory) public ViewModelProvider (ViewModelStore store, ViewModelProvider.Factory factory) 複製代碼
使用方法
<T extends ViewModel> T get(Class<T> modelClass) <T extends ViewModel> T get(String key, Class<T> modelClass) 複製代碼
該類用於覆寫函數建立ViewModel的實例對象
查看默認的NewInstanceFactory源碼能夠看到
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance(); // 經過反射建立對象
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
複製代碼
有時候你的數據屬於網絡請求過來的數據實體, 這個時候就須要用構造器來
AndroidViewModel
該類用於建立ViewModel實例的時候調用其構造函數(具有參數Application), 讓ViewModel中可使用Application
查看源碼:
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
// 經過具有參數Applicaiton的構造函數使用反射建立對象
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
複製代碼
onSaveInstanceState 和 ViewModel 區別
ViewModel本質上和onSaveIntance有區別.
ViewModel能夠保存複雜大量數據, onSaveIntance基於Bundle對象保存不能存儲大量數據(拋出異常)
ViewModel沒法在乎外銷燬時恢復數據, 只是配置變動(切換橫豎屏)時數據依然存在
須要額外擴展依賴
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha05'
複製代碼
綁定全部者的時候使用SavedStateVMFactory
工廠實例
mSavedStateViewModel = ViewModelProviders.of(this, new SavedStateVMFactory(this))
.get(SavedStateViewModel.class);
複製代碼
ViewModel須要建立一個構造函數
public class SavedStateViewModel extends ViewModel {
// 自定義的構造函數
public SavedStateViewModel(SavedStateHandle savedStateHandle) {
mState = savedStateHandle; // mState便可以讀寫數據, 不須要你去處理生命週期
}
}
複製代碼
SavedStateHandle
可以保存和查詢數據. 數據會和onSaveInstanse保存機制同樣不會丟失.
public <T> MutableLiveData<T> getLiveData(@Nullable String key)
public Set<String> keys()
public <T> T get(@NonNull String key)
public <T> void set(@NonNull String key, @Nullable T value)
public boolean contains(@NonNull String key)
public <T> T remove(@NonNull String key)
複製代碼
個人開源框架Net框架支持快速建立ViewModel
val model = getViewModel<Model>() // 僅僅配置變動數據恢復的
val model = getSavedModel<Model>() // 支持onSaveIntance意外銷燬恢復數據的
複製代碼
Model
class Model(saved: SavedStateHandle) : SavedViewModel(saved) {
var name: String?
get() = saved.get("name")
set(value) {
saved["name"] = value
}
}
複製代碼
提供一個SavedViewModel類用於快速繼承, saved即用於保存和恢復數據的存儲對象
若是不想介入Net, 能夠參考源碼
open class SavedViewModel(var saved: SavedStateHandle) : ViewModel()
inline fun <reified M : ViewModel> ViewModelStoreOwner.getViewModel(): M {
return ViewModelProvider(this).get(M::class.java)
}
inline fun <reified M : ViewModel> FragmentActivity.getSavedModel(): M {
return ViewModelProvider(
this,
SavedStateViewModelFactory(application, this)
).get(M::class.java)
}
inline fun <reified M : ViewModel> Fragment.getSavedModel(): M {
return ViewModelProvider(
this,
SavedStateViewModelFactory(activity!!.application, this)
).get(M::class.java)
}
複製代碼
使數據變成一個可被觀察狀態, 而且符合視圖的生命週期.
在活躍狀態觀察者能夠接受到事件, 不活躍狀態觀察者不會接收到事件. 若是生命週期全部者被破壞自動刪除觀察者.
活躍狀態即非onPause
或者onDestroy
IllegalArgumentException
繼承關係
java.lang.Object
↳ androidx.lifecycle.LiveData<T>
↳ androidx.lifecycle.MutableLiveData<T>
↳ androidx.lifecycle.MediatorLiveData<T>
複製代碼
所有公開方法
T getValue() // 返回當前值 boolean hasActiveObservers() // 是否有被激活的觀察者(處於活躍狀態) boolean hasObservers() // 是否有觀察者 void observe(LifecycleOwner owner, Observer<T> observer) void observeForever(Observer<T> observer) // 添加一個永遠處於活躍狀態的觀察者(而且不會自動刪除觀察者), 因此須要你本身刪除觀察者 // 重複添加同一個觀察者會拋出IllegalArgumentException void removeObserver(Observer<T> observer) // 刪除觀察者 void removeObservers(LifecycleOwner owner) // 刪除擁有同一個生命週期全部者的全部觀察者 複製代碼
提供覆寫函數
protected void onInactive ()
protected void onActive ()
protected void postValue (T value)
protected void setValue (T value)
複製代碼
這是一個抽象類, 咱們通常都是用他的子類MutableLiveData<T>
建立MutableLiveData
// 建立對象
var data = MutableLiveData<String>()
// 設置值
data.value = "設計師"
// 設置觀察者
data.observe(this@MainActivity, Observer {
Log.d("日誌", "(MainActivity.kt:28) ___ it = $it")
})
複製代碼
AppCompatActivity
自己就是實現了LifeCycleOwner
因此我這裏直接傳入This在數據變化後調用方法設置值(根據所處線程不一樣而調用不一樣的方法)
// 主線程
data.value = "設計師"
// 異步線程
data.postValue("設計師")
複製代碼
若是在觀察者以前設置值則設置觀察者以後會受到你設置以前最後一次設置的值, 注意最後一次.
這個繼承自liveData(abstract). 只是public
兩個私有方法(原本是protected
)
所有源碼:
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);
}
}
複製代碼
LiveData能夠存在多個觀察者
咱們能夠模仿MutableLiveData
本身自定義LiveData的邏輯
public class MyLiveData extends LiveData<String> {
/** * 活躍狀態 */
@Override protected void onActive() {
super.onActive();
}
/** * 非活躍狀態 */
@Override protected void onInactive() {
super.onInactive();
}
}
複製代碼
要想觸發這兩個方法必需要綁定觀察者.
其實實現LifecycleObserver
自己也可以實現生命週期的回調.
可是LiveData能夠能夠監聽值變化 (其實Kotlin也能)而且根據生命週期自動取消觀察者.
Transformations
提供兩個函數, 他的功能相似RxJava的map
和flatMap
操做符, 轉換LiveData的數據.
static <X, Y> LiveData<Y> map(LiveData<X> source, Function<X, Y> func) static <X, Y> LiveData<Y> switchMap(LiveData<X> trigger, Function<X, LiveData<Y>> func) 複製代碼
map示例:
final MyLiveData myLiveData = new MyLiveData();
myLiveData.observe(this, new Observer<String>() {
@Override public void onChanged(@Nullable String s) {
}
});
final LiveData<Integer> transformationLiveData =
Transformations.map(myLiveData, new Function<String, Integer>() {
/** * 若是想要該方法回調須要結果LiveData設置觀察者才行 * * @param input 源LiveData存儲的數據 * @return 最終返回的LiveData存儲的數據 */
@Override public Integer apply(String input) {
return 2;
}
});
transformationLiveData.observe(this, new Observer<Integer>() {
@Override public void onChanged(@Nullable Integer integer) {
}
});
複製代碼
switchMap示例
final LiveData<Integer> transformationLiveData =
Transformations.switchMap(myLiveData, new Function<String, LiveData<Integer>>() {
/** * @param input 源數據 * @return 返回結果等於switchMap的結果 */
@Override public LiveData<Integer> apply(String input) {
MutableLiveData<Integer> transformationLiveData = new MutableLiveData<>();
transformationLiveData.setValue(3);
return transformationLiveData;
}
});
複製代碼
總結:
二者區別即map返回的是一個類型, 而switchMap規定返回的是一個新的LiveData.
能夠看作map能夠替代switchMap, 由於MutableLiveData也是一個類型.
做爲Transformation的參數傳進去的LiveData若是以前就設置過Observer一樣會生效, 至關於有兩個觀察者.
能夠設置多個源LiveData
. 而後經過觀察者來同時監聽多個LiveData的變化
MediatorLiveData自己也是LiveData的一部分
<S> void addSource(LiveData<S> source, Observer<S> onChanged) // 添加源 <S> void removeSource(LiveData<S> toRemote) // 刪除源 複製代碼
示例
var data = MutableLiveData<String>()
var data2 = MutableLiveData<Int>()
// 這裏就是在data,data2變動值時通知MediatorLiveData也更新
mediatorLiveData.addSource(data, Observer { mediatorLiveData.value = 1 })
mediatorLiveData.addSource(data2, Observer { mediatorLiveData.value = 3 })
mediatorLiveData.observe(this, Observer {
// data或data2屬性變化都會在這裏被監聽
})
複製代碼
關於LiveData的應用我認爲只是針對應用後臺和前臺展現的應用場景
LiveData實現MVVM
有些人可能會說用LiveData來寫MVVM, 可是我以爲這有點扯淡了, LiveData只會在賦值對象的時候纔會通知監聽器, 對象中的屬性變化並不會.
並且就算你爲每一個數據都用LiveData寫個監聽器那也得在監聽器中綁定UI, 這和本身每次設置UI有什麼區別.
若是是對於ui的更新仍是推薦使用Databinding的數據綁定形式, 能夠結合LiveData實現前臺更新數據
binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, layout)
binding.lifecycleOwner = this
binding.m = model
複製代碼
Model
class Model{
val data = MutableLiveData<String>()
}
複製代碼
XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools">
<data>
<variable name="m" type="com.example.architecture.Model" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{m.data}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
複製代碼
這樣Databinding更新屬性就會具有LiveData的感知生命週期的功能, 只有處於前臺纔會當即更新ui.
Observable
和LiveData
區別
liveData還擁有官方的協程擴展庫, 能夠建立具有活躍狀態的協程的做用域, 具體請查看個人協程文章: Kotlin協程: Coroutine/Channel/Flow 以及實際應用
生命週期組件, 能夠將一個類賦予Activity生命週期.
實現接口LifecycleObserver
public class CusLifecycleObserver implements LifecycleObserver {}
複製代碼
綁定生命週期
lifecycleOwner.getLifecycle().addObserver(this);
複製代碼
而後就能夠經過註解來在生命週期時自動調用
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void removeLocationListener() {
if (mLocationManager == null) {
return;
}
mLocationManager.removeUpdates(mListener);
mLocationManager = null;
Log.i("日誌", "(BoundLocationListener.java:74) ___ removeLocationListener");
}
}
複製代碼
全部的生命週期狀態
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
複製代碼
執行順序
若是你想自定義LifecycleOwner也能夠
public class MyActivity extends Activity implements LifecycleOwner {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.markState(Lifecycle.State.CREATED);
}
@Override
public void onStart() {
super.onStart();
mLifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return new LifecycleRegistry(this);
}
}
複製代碼
這裏我繼承是Activity, 並不表明生命週期就只能是Activity的, 能夠是任何具備生命週期的組件(官方同時支持Service的生命週期).
只有一個函數
public abstract Lifecycle getLifecycle ()
複製代碼
這是控制生命週期狀態變動的控制器
public void addObserver (LifecycleObserver observer) // 添加觀察者 public void removeObserver (LifecycleObserver observer) // 刪除觀察者 public int getObserverCount () // 當前觀察者數量 public Lifecycle.State getCurrentState () // 當前狀態 public void markState (Lifecycle.State state) // 設置當前狀態, 通常用戶自定義LifecycleOwner使用 public void handleLifecycleEvent (Lifecycle.Event event) // 設置當前狀態, 和markState不一樣是這個若是參數狀態和當前狀態一直不會通知Observer觀察者 複製代碼
有五種狀態
Lifecycle.State CREATED
Lifecycle.State DESTROYED
Lifecycle.State INITIALIZED
.
Lifecycle.State RESUMED
Lifecycle.State STARTED
複製代碼
public boolean isAtLeast (Lifecycle.State state) // 若是當前聲明週期大於等於參數生命週期則返回true public static Lifecycle.State valueOf (String name) // 將字符串轉爲State 複製代碼
只能有一個或者沒有參數, 可是能夠增長一個LifecycleOwner
參數. 而且ON_ANY
註解的方法能夠增長第二個註解Event
. 該參數的做用只是判斷當前所處的生命週期.
class TestObserver implements LifecycleObserver {
@OnLifecycleEvent(ON_CREATE)
void onCreated(LifecycleOwner source) {}
@OnLifecycleEvent(ON_ANY)
void onAny(LifecycleOwner source, Event event) {}
}
複製代碼
上面提到了用註解來控制生命週期, 若是你當前使用的JDK是JDK8以上能夠選擇覆寫函數的形式來回調生命週期
不太推薦感受冗餘
須要另外導入一個依賴:
dependencies {
// Java8 support for Lifecycles
implementation "android.arch.lifecycle:common-java8:1.0.0"
}
複製代碼
而且再也不使用註解而是使用重寫方法, 而且實現DefaultLifecycleObserver
class TestObserver implements DefaultLifecycleObserver {
@Override
public void onCreate(LifecycleOwner owner) {
// your code
}
}
複製代碼