从源码看Jetpack(三)ViewModel一图流

八股一图流

一图流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

优点

  1. 当横竖屏发生切换时,activity会重建,但是ViewModel不需要重建。

  2. ViewModel可以避免内存泄漏问题,Activity destroy时会调用ViewModel的onCleared()方法。

  3. 可以解决同一个Activity的不同Fragment的数据共享问题。

ViewModel如何监听生命周期

  1. 在Activity的父类ComponentActivity构造方法中添加了一个Lifecycle的事件监听器
  2. onDestroy中会分发一个名为Lifecycle.Event.ON_DESTROY的事件。
  3. 当我们接收到这个事件后,就会判断我们的Activity是正常销毁还是因为配置文件而销毁。
  • 正常销毁的话,清除掉ViewModelStore中的数据
  • 配置文件修改,保存ViewModelStore中的数据

ViewModel的恢复流程

  1. 会把ViewModelStore这个对象保存在ComponentActivity的静态内部类中,不受Activity重建的影响
  2. 配置信息发生改变后,在Activity销毁前将ViewModelStore保存,在Activity重建后将ViewModelStore恢复。

ViewModel是单向绑定还是双向绑定?

  • 通常是单向绑定。持有了Model,将Model显示在View上,单向绑定View。
  • 在典型的架构中,ViewModel作为视图和数据模型之间的中介层,负责提供数据给视图展示,并接收来自视图的用户操作或事件。视图可以观察(订阅)ViewModel中的数据,以便及时更新UI,但通常无法直接修改ViewModel中的数据。

流程图

保存流程图

在这里插入图片描述

恢复流程图

在这里插入图片描述

获取流程图

在这里插入图片描述

看看ViewModel 类的代码

public abstract class ViewModel {
    // Can't use ConcurrentHashMap, because it can lose values on old apis (see b/37042460)
    @Nullable
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    private volatile boolean mCleared = false;
    
    //在ViewModel将 被清除时调用     
    //当ViewModel观察了一些数据,可以在这里做解注册 防止内存泄漏
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }

    @MainThread
    final void clear() {
        mCleared = true;
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // see comment for the similar call in setTagIfAbsent
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

    .......
}

ViewModel类是抽象类,clear()方法会在ViewModel将被清除时调用。ViewModel实例获取是通过ViewModelProvider类。

//ViewModelProvider

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
          this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                  ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                  : NewInstanceFactory.getInstance());
}

public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
    this(owner.getViewModelStore(), factory);
}

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}

ViewModelStoreOwner----ViewModel存储器持有者;

ViewModelStoreOwner的实现类有Activity/Fragment.

public interface ViewModelStoreOwner {
        //获取ViewModelStore,即获取ViewModel存储器
    ViewModelStore getViewModelStore();
}

ViewModelStore----ViewModel存储器,用来存储ViewModel

接下来看看ViewModelStore如何存储ViewModel以及ViewModel实例的获取

/**
 * 用于存储ViewModels.
 * ViewModelStore实例 必须要能 在系统配置改变后 依然存在。
 */
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);
    }
    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }
    /**
     * 调用ViewModel的clear()方法,然后清除ViewModel
     * 如果ViewModelStore的拥有者(Activity/Fragment)销毁后不会重建,那么就需要调用此方法
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

Factory----创建ViewModel实例的工厂

再看看ViewModel实例的工厂Factory—NewInstanceFactory:

public static class NewInstanceFactory implements Factory {
...
    @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);
        }
    }
}

ViewModelProvider–创建和获取 ViewModel 对象

最后使用ViewModelProvider().get(xxx.class)来获取自定义的ViewModel实例

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");
    
//拿到Key,也即是 ViewModelStore中的Map的用于存 ViewModel的 Key
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
    
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//从ViewModelStore获取ViewModel实例
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        //如果从ViewModelStore中获取到,直接返回
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
    //没有获取到,就使用Factory创建
        viewModel = (mFactory).create(modelClass);
    }
    //存入ViewModelStore 然后返回
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

以上逻辑:
先尝试从ViewModelStore中获取ViewModel实例。如果没有获取到,就使用Factory创建,然后存入ViewModelStore。

总结

  • Activity持有ViewModel,一个Activity可以有多个类型的ViewModel;
  • 同一个类型的ViewModel在Activity中有且只有一个实例;
  • 通过HashMap和工厂模式保证了单一类型ViewModel的单例;
  • ViewModel生命周期贯穿整个Activity,且不会重复创建。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值