阅读 1437

ViewModel/LiveData/LifeCycle介绍

早期这几个库并称为ArchitectureComponent, 后被并入Jetpack组件库之中. 本来不想写这篇文章觉得应该都会使用, 但这三个库对于构建一个具备健壮清晰的数据层的应用作用很大, 建议配合我上篇文章介绍的ROOM框架使用

androidx后内置LiveData/ViewModel/Lifecycle, 无需导入依赖

  1. LiveData: 感知活跃(onStart)和非活跃状态(onPause)的数据观察者

  2. ViewModel: 屏幕旋转自动保存数据, 或者意外销毁读写saveInstance数据. 保证数据安全

  3. Lifecyle: 可以监听生命周期, 默认Activity和Fragment已经实现lifecycleOwner, 常用于框架封装中的生命周期处理.

我平时项目开发必备框架

  1. Android上最强网络请求 Net
  2. Android上最强列表(包含StateLayout) BRV
  3. Android最强缺省页 StateLayout
  4. JSON和长文本日志打印工具 LogCat
  5. 支持异步和全局自定义的吐司工具 Tooltip
  6. 开发调试窗口工具 DebugKit
  7. 一行代码创建透明状态栏 StatusBar

参考文献

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) {}
 }
复制代码

在监听器中判断生命周期使用LifecycleEventObserver

lifecycle.addObserver(object : LifecycleEventObserver {
  override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
    when (event) {
      Lifecycle.Event.ON_ANY-> { }
    }
  }
})
复制代码