当前位置: 代码迷 >> 综合 >> ViewModel+LiveData总结
  详细解决方案

ViewModel+LiveData总结

热度:54   发布时间:2023-11-21 07:20:41.0

ViewMode+LiveData总结

Activity/Fragment只应关注UI,而不应关系操作逻辑,因此操作逻辑应放到Viewmodel中去
下面是我手画的数据流图:
在这里插入图片描述
首先有FragmentViewModelLivedata这三个对象。

  1. Fragment观察Viewmodel的Livedata数据,如果livedata的值改变会通知Frament。
  2. ViewModel获取数据(网络、数据库),然后设置Livedata的值
  3. Livedata的值改变就通知Fragment
  4. Fragment刷新界面

代码如下:
Fragment


import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.widget.TextView;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;/**
*
* @date 2020/9/19
*/
public class MyActivity extends AppCompatActivity {Handler messageHandler;MyViewModel myViewModel;Handler mainHandler;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final TextView textView = findViewById(R.id.textView);// 新建ViewModelmyViewModel = new MyViewModel();// 子线程HandlerThread handlerThread = new HandlerThread("");handlerThread.start();// 子线程HandlermessageHandler = new Handler(handlerThread.getLooper());// 主线程handlermainHandler = new Handler(getMainLooper());// 开启自自线程改变数据messageHandler.post(new Runnable() {@Overridepublic void run() {int i = 0;while (i < 100) {mainHandler.post(new Runnable() {@Overridepublic void run() {myViewModel.requestChangeText();}});try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}i++;}}});myViewModel.getmText().observe(this, new Observer<String>() {@Overridepublic void onChanged(final String s) {runOnUiThread(new Runnable() {@Overridepublic void run() {textView.setText(s);}});}});}
}

viewmodel


import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;import java.util.Observable;
import java.util.Random;/*** Describe:<p></p>* 描述:<p></p>** @date 2020/9/19*/
public class MyViewModel extends ViewModel implements IMyModelHelper {private MutableLiveData<String> mText = new MutableLiveData<String>();public MyViewModel() {}public MutableLiveData<String> getmText() {return mText;}@Overridepublic void requestChangeText() {changeText();}private void changeText(){getmText().setValue(new Random(10).toString());}
}
package com.loyal888.tets;/*** Describe:<p></p>* 描述:<p></p>** @date 2020/9/19*/
public interface IMyModelHelper  {
    void requestChangeText();
}

总结:数据通知可以使用Observer,实现进一步解耦合

MVP 和MVVM的区别

在这里插入图片描述

获取VidewModel实例

// 新建ViewModel
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

VideoModel的生命周期

系统首次调用 Activity 对象的 onCreate() 方法时请求 ViewModel。系统可能会在 Activity 的整个生命周期内多次调用 onCreate(),如在旋转设备屏幕时。ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁。

在当前生命周期为Destrory的时候,清除了mViewModelStore
在这里插入图片描述

ViewModel中使用Context

扩展AndroidViewModel

ViewModel 对象可以包含 LifecycleObservers,如 LiveData 对象。但是,ViewModel 对象绝不能观察对生命周期感知型可观察对象(如 LiveData 对象)的更改。 如果 ViewModel 需要 Application 上下文(例如,为了查找系统服务),它可以扩展 AndroidViewModel 类并设置用于接收 Application 的构造函数,因为 Application 类会扩展 Context。

ViewModel源码分析

1. ViewModelProvider.of(this)

  • 检查应用的上下文
  • 构造了AndroidViewModelFactory
  • 返回provider
   public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return of(activity, null);}@NonNull@MainThreadpublic static ViewModelProvider of(@NonNull FragmentActivity activity,@Nullable Factory factory) {
    // 1. 检查应用的上下文且必须是applicationApplication application = checkApplication(activity);if (factory == null) {
    // 2.构造了AndroidViewModelFactoryfactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);}// 3.返回provider// 3.1 注意这里的activity.getViewModelStore()return new ViewModelProvider(activity.getViewModelStore(), factory);}

2. activity.getViewModelStore()

public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
    throw new IllegalStateException("Your activity is not yet attached to the "+ "Application instance. You can't request ViewModel before onCreate call.");}if (mViewModelStore == null) {
    // 获取上一次配置改变保存的NonConfigurationInstances,比如屏幕旋转NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {
    // Restore the ViewModelStore from NonConfigurationInstances// 配置改变,viewModelStore不空,直接使用// 这个viewModelStore是在哪里保存的?见下文mViewModelStore = nc.viewModelStore;}if (mViewModelStore == null) {
    // 第一次来就新建一个ViewModelStore,保存的上一次的状态// 新建来之后保存到哪里?见下文mViewModelStore = new ViewModelStore();}}return mViewModelStore;}

3.保存ViewModelStore

getLastNonConfigurationInstance();
保存呢? 调用的是ConponentActivity中的onRetainNonConfigurationInstance,调用时机介于onStoponDestroy中间,onSaveInstance之后。

public final Object onRetainNonConfigurationInstance() {
    Object custom = onRetainCustomNonConfigurationInstance();// 这里就是上文的new出来的mViewModelStoreViewModelStore viewModelStore = mViewModelStore;if (viewModelStore == null) {
    // No one called getViewModelStore(), so see if there was an existing// ViewModelStore from our last NonConfigurationInstanceNonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {
    viewModelStore = nc.viewModelStore;}}if (viewModelStore == null && custom == null) {
    return null;}NonConfigurationInstances nci = new NonConfigurationInstances();nci.custom = custom;// 把mViewModelStore保存到NonConfigurationInstances中去nci.viewModelStore = viewModelStore;return nci;}

4. 获取上一次保存的viewmodel

public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
    throw new IllegalStateException("Your activity is not yet attached to the "+ "Application instance. You can't request ViewModel before onCreate call.");}if (mViewModelStore == null) {
    NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {
    // Restore the ViewModelStore from NonConfigurationInstances// 注意上面这句英文mViewModelStore = nc.viewModelStore;}if (mViewModelStore == null) {
    mViewModelStore = new ViewModelStore();}}return mViewModelStore;}

5. 获取ViewModel
ViewModelProviders.of(this).get(MyViewModel.class);

public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();if (canonicalName == null) {
    throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");}return get(DEFAULT_KEY + ":" + canonicalName, modelClass);}public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    // 上文提到构建出来的mViewModelStore,从HashMap取出实例ViewModel viewModel = mViewModelStore.get(key);if (modelClass.isInstance(viewModel)) {
    //noinspection unchecked// 有就返回return (T) viewModel;} else {
    //noinspection StatementWithEmptyBodyif (viewModel != null) {
    // TODO: log a warning.}}if (mFactory instanceof KeyedFactory) {
    viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);} else {
    // 没有反射创建出来viewModel = (mFactory).create(modelClass);}// 将mViewModelStore保存到HashMap,保存的时候会销毁旧对象mViewModelStore.put(key, viewModel);//noinspection uncheckedreturn (T) 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) {
    // 旧viewmodel会被清除!!!oldViewModel.onCleared();}}final ViewModel get(String key) {
    return mMap.get(key);}Set<String> keys() {
    return new HashSet<>(mMap.keySet());}/*** Clears internal storage and notifies ViewModels that they are no longer used.*/public final void clear() {
    for (ViewModel vm : mMap.values()) {
    vm.clear();}mMap.clear();}
}
总结: VieModelStore存在于FragmentActivity中,在配置更改导致Activity销毁前通过onRetainNonConfiguraionInstance将数据对象保存,并在重建时通过getLastNonConfigurationInstance将数据还原回来,从而保证了Activity内ViewModelStore 的唯一性一致性

LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

源码分析

构造方法

 public LiveData(T value) {
    // 保存具体的值mData = value;// 当前版本mVersion = START_VERSION + 1;}
}

观察Livedata

 myViewModel.getmText().observe(this, new Observer<String>() {
    @Overridepublic void onChanged(final String s) {
    runOnUiThread(new Runnable() {
    @Overridepublic void run() {
    textView.setText(s);}});}});

observe了什么

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    // ignorereturn;}LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);// mObservers 添加了当前观察者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);}

数据改变setValue之后

 protected void setValue(T value) {
    assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
    mDispatchInvalidated = true;return;}mDispatchingValue = true;do {
    mDispatchInvalidated = false;if (initiator != null) {
    considerNotify(initiator);initiator = null;} else {
    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
    // 通知并回调每一个观察者的回调方法considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {
    break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}  

Transformations#map()

eg:

public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,@NonNull final Function<X, Y> mapFunction) {
    final MediatorLiveData<Y> result = new MediatorLiveData<>();// X改变了,Y继续result.addSource(source, new Observer<X>() {
    @Overridepublic void onChanged(@Nullable X x) {
    result.setValue(mapFunction.apply(x));}});return result;}

Transtormations#switchMap

 MutableLiveData userIdLiveData = ...;LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->repository.getUserById(id));void setUserId(String userId) {
    this.userIdLiveData.setValue(userId);}

总结,使用ViewModel和LiveData的优势

1 不需要手动处理生命周期
ViewModel和LiveData本身是生命周期可感知的

2 确保View可以及时拿到数据状态

LiveData遵循观察者模式,数据更改时,LiveData会通知对象。这也是它的优势,如果UI改变很多,MVP就需要写很多的接口。View被动的接受Presenter的指令。

3 减少内存泄漏

LiveData绑定了Lifecycle对象,ViewModel 在生命周期方法中自行清理回收

4 共享资源
单例使用ViewModel和LiveData,可以在程序中共享他们,例两个fragment共享一个ViewModel

1、建议添加LiveData和ViewModel的详细使用介绍,方便大家知道一些高级使用方式。比如LiveData对数据的拼装等。

2、文档不太能体现出和MVP的对比及优势。比如ViewModel和View解耦之类的。