ViewModel/LiveData/LifeCycle使用

這幾個庫理論上應該都會使用, 我認爲屬於JetPack中的基礎庫, 早期稱爲ArchitectureComponent, 後被併入Jetpack組件庫之中.php

androidx內置LiveData/ViewModel/Lifecycle, 無需導入依賴.html

  1. LiveData: 感知活躍(onStart)和非活躍狀態(onPause)的數據觀察者java

  2. ViewModel: 屏幕旋轉自動保存數據, 或者意外銷燬讀寫saveInstance數據android

  3. Lifecyle: 能夠監聽生命週期, 默認Activity和Fragment已經實現lifecyclegit

參考文獻github

ViewModel

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就實現了LifeCycleOwnerViewModelStoreOwner

public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner, OnBackPressedDispatcherOwner { 
          //...
        }
複製代碼

同時Fragment也實現了ViewModelStoreOwner

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是否某些內存 複製代碼

ViewModelProvider

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.Factory

該類用於覆寫函數建立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 區別

  • 須要序列化和反序列化, 佔用空間大而且耗時
  • 主線程處理
  • 進程死亡也能夠不影響

Saved State

ViewModel本質上和onSaveIntance有區別.

  1. ViewModel能夠保存複雜大量數據, onSaveIntance基於Bundle對象保存不能存儲大量數據(拋出異常)

  2. 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
        }
}
複製代碼
  1. 提供一個SavedViewModel類用於快速繼承, saved即用於保存和恢復數據的存儲對象

  2. 若是不想介入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)
    }
    複製代碼

LiveData

使數據變成一個可被觀察狀態, 而且符合視圖的生命週期.

在活躍狀態觀察者能夠接受到事件, 不活躍狀態觀察者不會接收到事件. 若是生命週期全部者被破壞自動刪除觀察者.

活躍狀態即非onPause或者onDestroy

  1. 添加已被銷燬的生命週期全部者, 會忽略
  2. 添加已經被添加過的生命週期全部者也會忽略
  3. 若是觀察者已經被另外一個liveData添加過, 會拋出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("設計師")
複製代碼

若是在觀察者以前設置值則設置觀察者以後會受到你設置以前最後一次設置的值, 注意最後一次.

MutableLiveData

這個繼承自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能夠存在多個觀察者

自定義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

Transformations 提供兩個函數, 他的功能相似RxJava的mapflatMap操做符, 轉換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一樣會生效, 至關於有兩個觀察者.

MediatorLiveData

能夠設置多個源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屬性變化都會在這裏被監聽
})
複製代碼

結合Databinding

關於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.

ObservableLiveData區別

  • LiveData 能夠延期執行(等待活躍狀態)
  • Observable 雙向數據綁定, LiveData只能單向數據觀察者
  • Observable監聽器若是不是綁定ui沒法保證ui沒有銷燬

liveData還擁有官方的協程擴展庫, 能夠建立具有活躍狀態的協程的做用域, 具體請查看個人協程文章: Kotlin協程: Coroutine/Channel/Flow 以及實際應用

Lifecycle

生命週期組件, 能夠將一個類賦予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的生命週期).

LifecycleOwner

只有一個函數

public abstract Lifecycle getLifecycle ()
複製代碼

LifecycleRegistry

這是控制生命週期狀態變動的控制器

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

有五種狀態

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
     }
 }
複製代碼
相關文章
相關標籤/搜索