【Jetpack】LiveData+ViewModel

相关博客参考

Lifecycle源码解析:https://juejin.im/post/6847902220755992589#heading-13
LiveData源码解析:https://juejin.im/post/6844903796657782791
ViewModel源码解析:https://juejin.im/post/6844904169401221134

一 简介

Lifecycle 是 Jetpack 整个家族体系内最为基础的内容之一,为上层的LiveData、ViewModel等等更上层的组件提供监听 Activity、Fragment、Service、甚至 Process 的生命周期变化的统一方式。
LiveData 是 Jetpack 家族的一种响应式开发框架,类似框架有还RxJava等。以数据驱动的方式更新UI,并且由于其基于Livecycle,能够感知组件生命周期变化,只会更新活跃的组件的状态,并在组件销毁时能自动解除对该组件的监听。
ViewModel: Activity或Fragment支持以数据以ViewModel的形式存储在内部,于是ViewModel常常作为组件相关的多个LiveData的存储载体。ViewModel 里面的数据不会因为屏幕的旋转或者其他配置(比如切换到多窗口模式)而丢失。

 

LiveData

一、LiveData简介

LiveData是google官方架构JetPack系列的一个响应式开发框架,LiveData是一个可以被观察的数据持有者类。说到响应式开发或者说观察者就不免想到RxJava,RxJava将观察者模式运用的炉火纯青。但LiveData和RxJava的定位是不一样的,LiveData主要用于搭建MVVM架构,并在其中作为数据持有者,LiveData能监听组件的生命周期变化,这样一来只会更新处于活跃状态的组件。

LiveData的特点:

1)采用观察者模式自动提示UI更新。

2)不需要手动处理生命周期,不会因为Activity的销毁重建而丢失数据。

3)不会出现内存泄漏。

4)不需要手动取消订阅,Activity在非活跃状态下(销毁、finish之后)不会收到数据更新信息。

二、LiveData用法

1)LiveData往往结合于ViewModel使用,对于ViewModel的分析之前已经进行分析了,这里不再过多描述。首先在ViewModel中创建LiveData,代码如下:

class MainViewModel : ViewModel() {

    private val repertory: MainRepository by lazy {
        MainRepository()
    }

    var data: MutableLiveData = MutableLiveData()

    fun getDataFromServer() {

        repertory.getDataFromServer(data)

    }
}

这里采用的是MutableLiveData,它是LiveData的实现类,LiveData是一个抽象类。

2)在Activity中观察LiveData的数据变化。代码如下:

class MainActivity : AppCompatActivity() {
    private lateinit var mModel: MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initData()
    }

    private fun initData() {
        mModel = ViewModelProviders.of(this)[MainViewModel::class.java]
        mModel.data?.observe(this, Observer {
            val mainAdapter = MainAdapter(this, it)
            val linearLayoutManager = LinearLayoutManager(this)
            rv.layoutManager = linearLayoutManager
            rv.adapter = mainAdapter
        })
        mModel.getDataFromServer()
    }
}

3)对LiveData进行赋值,代码如下:

fun postData() {
        mModel.data.postValue(JsonBean(ArrayList(), 0, ""))
    }

三、源码分析

1)首先先从实例化MutableLiveData入手,MutableLiveData是LiveData的实现类,源码如下:

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提供两个赋值方法:postValue和setValue,而这两个方法直接调用父类中的方法。所以看一下父类中这两个方法的具体实现

setValue方法必须在主线程调用,调用只有LiveData就持有新的数据了。

postValue方法同样是更新LiveData持有的数据,但区别在于postValue方法是单独采用Runnable通过主线程handler发送给主线程更新数据,这样一来postValue就可以在异线程更新数据了。其实postValue最终更新数据还是走的setValue方法。

  @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

2)分析在Activity中订阅LiveData的方法observe,此方法接收两个参数,一个LifecycleOwner和Observer,代码如下:

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        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);
    }

从中我们可以发现方法首先会判断当前视图状态是否已经是”DESTROYED“状态,在分析订阅方法之前先分析一下LifecycleOwner这个接口。

public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

在这个接口中只有一个方法用于返回Lifecycle。查看一下接口的实现类可以发现v4和v7包下的Acvitity和Fragment都实现了这个接口。接下来看一下Lifecycle这个抽象类。

public abstract class Lifecycle {
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);
    @MainThread
    @NonNull
    public abstract State getCurrentState();
.....省略部分代码
}

类中定义了添加和移除订阅者的方法,同时还包括订阅者的生命周期状态信息。而Lifecycle的唯一实现类是LifecycleRegistry,代码如下。

public class LifecycleRegistry extends Lifecycle {
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();
  
    private final WeakReference<LifecycleOwner> mLifecycleOwner;
    private int mAddingObserverCounter = 0;

    private boolean mHandlingEvent = false;
    private boolean mNewEventOccurred = false;
    private ArrayList<State> mParentStates = new ArrayList<>();
    public LifecycleRegistry(@NonNull LifecycleOwner provider) {
        mLifecycleOwner = new WeakReference<>(provider);
        mState = INITIALIZED;
    }
......省略部分代码

    private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    }

    private State calculateTargetState(LifecycleObserver observer) {
        Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

        State siblingState = previous != null ? previous.getValue().mState : null;
        State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
                : null;
        return min(min(mState, siblingState), parentState);
    }

    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

    private void popParentState() {
        mParentStates.remove(mParentStates.size() - 1);
    }

    private void pushParentState(State state) {
        mParentStates.add(state);
    }

    @Override
    public void removeObserver(@NonNull LifecycleObserver observer) {
        mObserverMap.remove(observer);
    }
    @NonNull
    @Override
    public State getCurrentState() {
        return mState;
    }

    static State getStateAfter(Event event) {
        switch (event) {
            case ON_CREATE:
            case ON_STOP:
                return CREATED;
            case ON_START:
            case ON_PAUSE:
                return STARTED;
            case ON_RESUME:
                return RESUMED;
            case ON_DESTROY:
                return DESTROYED;
            case ON_ANY:
                break;
        }
        throw new IllegalArgumentException("Unexpected event value " + event);
    }

    private static Event downEvent(State state) {
        switch (state) {
            case INITIALIZED:
                throw new IllegalArgumentException();
            case CREATED:
                return ON_DESTROY;
            case STARTED:
                return ON_STOP;
            case RESUMED:
                return ON_PAUSE;
            case DESTROYED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }

    private static Event upEvent(State state) {
        switch (state) {
            case INITIALIZED:
            case DESTROYED:
                return ON_CREATE;
            case CREATED:
                return ON_START;
            case STARTED:
                return ON_RESUME;
            case RESUMED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }
.....省略部分代码
}

先来看一下主要的成员变量mObserverMap和mLifecycleOwner,mObserverMap是一个Map结构,以观察者为key存储观察者状态。mLifecycleOwner是一个弱引用,持有LifecycleOwner,其实LifecyleOwner就是Activity或者Fragment。前面说到过Activity中会实现LifecycleOwner接口,其实追踪到源码发现SupportActivity实现了LifecycleOwner接口,同时声明变量LifecycleRegistry,代码如下:

 private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

由此一来LifecycleRegistry就持有Activity的弱引用了,这样一来既能监听Activity的生命周期同时也不会造成内存泄漏。接下来看关键的订阅和取消订阅方法,取消订阅很简单就是将观察者移除Map集合,订阅方法会先校验观察者的生命周期状态,同时从软引用中获取LifecycleOwner,如果为空的话则说明界面已经被销毁了,则不需要进行订阅了。否则进行订阅操作。 现在回到前面继续分析LiveData的订阅操作,订阅操作会将owner和observer统一包装成LifecycleBoundObserver,这是Lifecycle真正的订阅者。

 class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

类中封装了对于Lifecycle的状态赋值操作和状态改变对观察者进行取消订阅操作。最后将LifecycleBoundObserver传入LifecycleRegistry完成订阅。整体的订阅流程就分析完了。

3)Observer响应获取数据变化流程分析。 分析完订阅流程接下来分析LiveData如何响应数据变化通知给订阅者,这里需要从setValue方法入手。

   protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

 private 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<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

调用setValue方法后会调用dispatchingValue方法循环通知订阅者响应数据变化。

三、LiveData特点原理总结

1)采用观察者模式自动提示UI更新: 由于采用订阅方式获取数据变化所以自动获取数据更新。

2)不需要手动处理生命周期,不会因为Activity的销毁重建而丢失数据: 会自动重新订阅。

3)不会出现内存泄漏: Lifecycle持有的是Activity(Fragment)的弱引用。

4)不需要手动取消订阅,Activity在非活跃状态下(销毁、finish之后)不会收到数据更新信息: LifecycleRegistry会回调Activity的状态,在onDestory之后LiveData自动取消订阅。

四、核心原理

1)observe做为入口,使用LifecycleBoundObserver把观察者和被观察者包装在一起绑定wrapper作为观察者

2)绑定完成后,使用setValue与postValue通知观察者

3)setValue中

dispatchingValue(null) 
if (initiator != null) 
参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
通知所有的观察者通过遍历 mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的 LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。

considerNotify()
先用2个if判断出被观察者对应的activity状态是否为显示
 发送通知 onChanged()被调用 

4) postValue中 切换线程到主线程中去执行setValue

ViewModel

一 概述

ViewModel 在Activity或者Fragment生命周期内只有一个的存储数据。ViewModel 里面的数据不会因为屏幕的旋转或者其他配置(比如切换到多窗口模式)而丢失。但是在正常的finish()或者按返回键的时候,在Activity或者Fragment走到onDestroy的时候回清除ViewModel里面的数据,避免内存泄漏。虽然屏幕旋转Activity也会走onDestroy,但是会判断是否是因为屏幕旋转而导致的。所以ViewModel是一个很合格的存储数据的类

 

二 ViewModel生命周期

ViewModel 对象存在的时间比Activity的生命周期要长,禁止在ViewModel的持有Activity、Fragment、View等对象,这样会引起内存泄漏。如果需要在ViewModel中引用Context的话,google为我们提供了AndroidViewModel 类来供我们使用。

三 ViewModel的好处

  • 不会因为屏幕旋转或者其他配置改变(比如切换到多窗口模式)而销毁,避免数据重新创建,比如网络数据重新加载的情况
  • 当Activity或者Fragment的正常销毁的时候,自动清除数据,也就是绑定了Activity或者Fragment的生命周期,避免了内存泄漏,
  • 多个Fragment之间或者Activity和Fragment之间更好地传递数据,进行交互
  • 减少Activityu或者Fragment的压力,Activityu或者Fragment的只是显示数据的界面,帮助Activity和Fragment处理一些数据逻辑
  • 也可以new ViewModle的,new出来的 基本上就没有ViewModle的特性了。相当于一个成员属性了

Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的情况。Activity和Fragment的之间互相调用,下面是一个Activity和两个Fragment之间的互相调用

3.1.1 构建一个Avtivity

class ViewModelDemoActivity : AppCompatActivity() {
    // 创建以Activity为维度的ViewModel
    private val viewModel: DemoViewModel by lazy { ViewModelProvider(this).get(DemoViewModel::class.java) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var binding = DataBindingUtil.setContentView<ActivityViewmodelDemoBinding>(
                this,
                R.layout.activity_viewmodel_demo
        )
        viewModel.dataLive.observe(this, object : Observer<String> {
            override fun onChanged(s: String?) {
                // 当横竖屏变换时,会重新走这里,毕竟是View也都重新绘制了,只不过user里面立马有值
                tv_name.text = s
            }
        })

        tv_name.setOnClickListener {
            // activity 里面的点击去改变值
            viewModel.dataLive.value = "Activity触发的改变"
        }
        viewModel.getName()
    }

    companion object {
        fun startMe(activity: Activity) {
            activity.startActivity(Intent(activity, ViewModelDemoActivity::class.java))
        }
    }
}

3.1.2 ViewModel的代码

class DemoViewModel : ViewModel() {
     val dataLive: MutableLiveData<String> =
         MutableLiveData<String>()


    fun getName(){
        viewModelScope.launch {
            delay(1000)
            dataLive.value = "王者荣耀"
        }
    }
}

3.1.3 布局文件

<?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">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ED6E6E"
            android:textSize="30sp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <fragment
            android:id="@+id/one"
            android:name="com.nzy.mvvmsimple.viewmodel.ShareOneFragment"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="@+id/guidline"
            app:layout_constraintTop_toBottomOf="@+id/tv_name" />

        <fragment
            android:id="@+id/two"
            app:layout_constraintTop_toBottomOf="@+id/tv_name"
            android:name="com.nzy.mvvmsimple.viewmodel.ShareTwoFragment"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="@+id/guidline"
            app:layout_constraintRight_toRightOf="parent"
            />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guidline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.5" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 意: 两个Fragment获取ViewModel的维度,要以Activity为维度

class ShareOneFragment : Fragment() {
    // 创建以Activity为维度的ViewModel,注意 这里是 requireActivity() 不是 getActivity(),requireActivity()不可能为空,getActivity()有可能为空
    private val viewModel: DemoViewModel
            by lazy { ViewModelProvider(requireActivity()).get(DemoViewModel::class.java) }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_share_one, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        // 这里传入是 viewLifecycleOwner(getViewLifecycleOwner()),而不会Fragment本身
        viewModel.dataLive.observe(viewLifecycleOwner, Observer {
            tv_name_one.text = it
        })

        // 在 FragmentOne 中去改变值
        tv_one.setOnClickListener {
            viewModel.dataLive.value = "Fragment-One,改变的值"
        }
    }

    companion object {
        @JvmStatic
        fun newInstance() =
            ShareOneFragment()
    }
}

可以发现很轻松的通过这个来实现数据的共享更改,再利用databinding实现ui的更新

github的demo

四 ViewModel 和 onSaveInstanceState 区别

4.1 ViewModel

  1. 缓存在内存中的,相当于本地缓存和网络缓存读写比较快

  2. 可以存较大的值,比如bitmap、大对象等等

  3. 数据绑定了Activity或者Fragment的生命周期,当Activity正常关闭的时候,都会清除ViewModel中的数据.比如

    • 调用finish()

    • 按返回键退出,

    • 用户直接杀进程或者是放后台内存不足,被回收了

  4. 在Activity旋转或者其他配置改变的时候,ViewModel里面是还有值得,不会销毁,

  5. ViewModel也可以使用本地存储,通过SavedStateHandle实现的,使用SavedStateViewModelFactory这个工厂,这里就不多介绍了,已经是正式版本了,引用是implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0

4.2 onSaveInstanceState

  1. 仅适合可以序列化再反序列化的少量数据
  2. 不适合数量可能较大的数据,如用数组或Bitmap。可以存一些简单的基本类型和简单的小对象、例如字符串,和一些id
  3. 会把数据存储到磁盘上

注意 对于复杂的大型数据,请使用 数据库 或者 SharedPreferences

五 ViewModel源码解析

5.1 源码

ViewModel的源码很少,基本上就是一个map 里面用来存储关于协程和SavedStateHandleController,onCleared() 方法是供我们自己调用,就是当Activity或者Fragmengt的关闭的时候,需要清理一些资源,比如Rxjava的流

//来存储 一些东西,当Activity 关闭的时候 会清除这里的数据
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    private volatile boolean mCleared = false;

    //来存储 一些东西,当Activity 关闭的时候 自己实现去清楚一些数据,比如Rxjava中的流
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }

5.1.1 获得ViewModelProvider

private val viewModel: DemoViewModel by lazy { ViewModelProvider(this).get(DemoViewModel::class.java) }

看ViewModelProvicder的构造方法

//创建一个ViewModelProvider , 用来创建ViewModels的,并将其保留在给定ViewModelStoreOwner的存储区中,如果owner是 HasDefaultViewModelProviderFactory 的子类,就用HasDefaultViewModelProviderFactory的工厂,像Fragment 和 ComponentActivity 都是实现了HasDefaultViewModelProviderFactory的接口 
 public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
    
 public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

上面默认的方法是; 用来创建ViewModels的,并将其保留在给定ViewModelStoreOwner的存储区中,如果owner是 HasDefaultViewModelProviderFactory 的子类,就用HasDefaultViewModelProviderFactory的工厂,像Fragment 和 ComponentActivity(是FragmentActivity的爹,AppCompatActivity的爷爷) 都是实现了HasDefaultViewModelProviderFactory的接口,获取到的Frctory是 SavedStateViewModelFactory。 否则就用NewInstanceFactory去创建ViewModel,比如需要我们在ViewModel中传递参数的时候,我们可以写自己的Factory继承NewInstanceFactory,走我们自己方法Create()

5.1.1.1 ComponentActivity中获取Factory的方法

public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        // 看这个activity是否已经attache到application
        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 (mDefaultFactory == null) {
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this,
                    getIntent() != null ? getIntent().getExtras() : null);
        }
        return mDefaultFactory;
    }

5.1.1.2 Fragment中获取Factory的方法

    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        if (mFragmentManager == null) {
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        if (mDefaultFactory == null) {
            mDefaultFactory = new SavedStateViewModelFactory(
                    requireActivity().getApplication(),
                    this,
                    getArguments());
        }
        return mDefaultFactory;
    }

5.1.2 自己定义的Factory

private val viewModel:UserViewModel by lazy { ViewModelProvider(this,UserViewModelFactory(repository)).get(UserViewModel::class.java) }
class UserViewModelFactory(
    private val repository: UserRepository
) : ViewModelProvider.NewInstanceFactory() {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        // 传入一个 Repository 参数
        return UserViewModel(repository) as T
    }
}

5.1.3 ViewModelStoreOwner: 存储ViewModel的拥有者

Fragment 和 ComponentActivity(是FragmentActivity的爹,AppCompatActivity的爷爷)都实现了 ViewModelStoreOwner 这个接口,

public interface ViewModelStoreOwner {
// ViewModelStore 是用来存储 ViewModel的实例的
    @NonNull
    ViewModelStore getViewModelStore();
}

5.1.3.1 ComponentActivity中的获得 ViewModelStroe 的方法

 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整个activity都装在里面了,NonConfigurationInstances是跟配置改变没有关系的一个实例。
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                //从NonConfigurationInstances 恢复 ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            // 如果为null,证明从来没有创建过,重新new 出来
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

5.1.3.2 在看一下ComponentActivity:: onRetainNonConfigurationInstance

public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        
        if (viewModelStore == null) {
           // 如果是null,说明以前没有调用过 getViewModelStore()方法,也就是没有调用过ViewModelProvider(requireActivity()).get(DemoViewModel::class.java)的方法来获取  ViewModel。所以我们看一下最后一个的NonConfigurationInstance里面是否存在viewModelStore
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
            // 若果nc 不等于null,就证明以前存储过,所以从这里取出来
                viewModelStore = nc.viewModelStore;
            }
        }
        // custom这个返回null,子类也没重写他的方法,所以是必须是null
        if (viewModelStore == null && custom == null) {
            return null;
        }

        // 如果viewModelStore不是null,也就是说最后一个NonConfigurationInstance里面有值,直接new出来NonConfigurationInstances并赋值,返回出去
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
       return nci;
}

然后看看 NonConfigurationInstances类,是ComponentActivity的一个静态内部类,用来存储viewModelStore的,无论配置是否改变,这个类的实例不会改,里面的ViewModelStore不会消失

  static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

5.1.3.3 retainNonConfigurationInstances 方法执行来存贮NonConfigurationInstances,返回结果就是NonConfigurationInstances,同时把NonConfigurationInstances存储到ActivityClientRecord中去,ActivityClientRecord是一个Activity的记录本。之后在Activity的Attach的时候,会把NonConfigurationInstances赋值给成员变量

在Activity调用onDestroy的之前会调用activity的retainNonConfigurationInstances

 NonConfigurationInstances retainNonConfigurationInstances() {
     ....
 }

总结一下:

  • 先通过NonConfigurationInstances来拿ViewModelStore,NonConfigurationInstances是一个静态内部类,不会因为配置改变(比如屏幕旋转),而重新创建
  • 如果NonConfigurationInstances没有拿到,证明这就是个新的ViewModelStore,所以直接走创建ViewModelStore流程

5.1.4 ViewModelStore 用来存储ViewModel的容器,,里面有个HashMap,用来存储ViewModel的,存储的key下面会讲到

public class ViewModelStore {

//  这个就是存储ViewModel的Hashmap
    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的里面的东西
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

5.1.5 获得ViewModel

 public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    // 获得 viewmodel这个类的全限定名
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        // 用一个DEFAULT_KEY常量 + 一个这个类的全限定名当做key
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

继续看get(String,Class) 方法

 public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 你可以认为mViewModelStore就是个map,上面也讲了,其实它里面就是一个map来存储ViewModel的
        // 从map里面拿到 拿到这个 ViewModel
        ViewModel viewModel = mViewModelStore.get(key);
        // viewModel 这个对象是否可以转化成这个类,如果 viewModel 是null的话,这里也返回false
        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // mFactory 如果不是自己实现的话,那就是SavedStateViewModelFactory 实现于 KeyedFactory,所以第一次拿的时候 ,走到这里
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        // 把获取到的ViewModel缓存到HashMap中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

5.1.6 在什么时候清除ViewModel

当 ComponentActivity 的构造方法中有以下代码,当Activity走到destroy的时候清楚ViewModel,里面有个isChangingConfigurations方法,表示 是否是配置改变引起的(比如 Activity屏幕旋转),如果是就不清除。

 getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

 

总结:

数据恢复原理

1、ComponentActivity
onRetainNonConfigurationInstance()保存状态  转屏时自动调用
getLastNonConfigurationInstance()恢复状态

2、获取viewModel
model = ViewModelProviders.of(getActivity()).get(NameViewModel.class);

3、ViewModelProviders.of()

保存了ViewModelStore和Factory并返回ViewModelProvider

参数1:getViewModelStore()方法中
从Activity的NonConfigurationInstances中取ViewModelStore,取不到就new一个
参数2:Factory中反射生成ViewModel实例

4、Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就一直在,也就避免了横竖屏切换时的数据丢失.

5、public ComponentActivity() 构造方法中clear()

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值