0
点赞
收藏
分享

微信扫一扫

Android-ViewModel源码分析

简介

ViewModel是JetPack生命周期管理库中的一个组件。它可以提供并且管理数据,可感知生命周期,同时不会随着配置(eg:屏幕旋转导致的Activity重新创建)变更而改变。 使用它可以方便的将UI界面和数据逻辑剥离开来,从而达到 UI只负责显示数据和处理用户操作,ViewModel负责提供、管理数据以及通讯。 典型使用场景:

  • 作为数据持有和管理者(eg:处理网络请求);
  • Fragment之间的通信;
  • ViewModel代替加载器(eg:CursorLoader)。

生命周期

官方对其生命周期的描述如下:

ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 activity,是在 activity 完成时;而对于 fragment,是在 fragment 分离时。

生命周期概括起来就是:从Activity第一次创建ViewModel,直至Activity销毁,ViewModel都一直存在。

基本使用

定义ViewModel:

class CustomModel() : ViewModel() {
    var data = 0
}

初始化和使用:

val customModel = ViewModelProvider(this).get(CustomModel::class.java)
customModel.data = 100;
findViewById<TextView>(R.id.tv).text = "${customModel.data}"

注意:务必不要直接(使用New)创建ViewModel,因为ViewModelProvider是确保ViewModel实例唯一性(同Activity内)和生命周期的关键。

那么如何创建需要初始化参数的ViewModel呢?答案是使用ViewModelProvider.Factory,一个工厂模式:

class CustomModel(data: Int) : ViewModel() {
    
    var data = 0
    init {
        this.data = data
    }
}

class CustomModelFactory(data: Int) : ViewModelProvider.Factory {
    var data = 0
    init {
        this.data = data
    }
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return CustomModel(data) as T
    }
}

使用:

val customModel = ViewModelProvider(this, CustomModelFactory(1000)).get(CustomModel::class.java)
findViewById<TextView>(R.id.tv).text = "${customModel.data}"

源码分析

接下来我们从ViewModel的源码进行分析:

ViewModel的创建

上文中我们说过,必须使用ViewModelProvider去创建ViewModel。这是确保ViewModel实例唯一性和生命周期的关键。那么我们就看一看ViewModelProvider是如何创建ViewModel的。

ViewModelProvider提供了三个构造函数:

  • ViewModelProvider(ViewModelStoreOwner);
  • ViewModelProvider(ViewModelStoreOwner, Factory);
  • ViewModelProvider(ViewModelStore, Factory);

在代码中最终都是通过ViewModelProvider(ViewModelStore, Factory)创建实例:

///构造方法一
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;
}

可以看到:构造方法一和二都是通过调用改造方法实现的。

构造方法一:首先获取ViewModelStore,然后判断ViewModelStoreOwner是否有创建ViewModel的工厂方法,有则直接使用(下文详细分析)。没有就是使用NewInstanceFactory。 构造方法二和一类似,也是首先获取ViewModelStore,只不过是多了个Factory参数。

ViewModelStoreOwner和ViewModelStoreOwner

我们先看ViewModelStoreOwner和ViewModelStoreOwner。

public interface ViewModelStoreOwner {
    @NonNull
    ViewModelStore getViewModelStore();
}

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());
    }

    /**
     *  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();
    }
}

源码很简单:ViewModelStoreOwner就是一个接口,而ViewModelStore则有了一些内容:它通过一个HashMap持有并管理者ViewModel,并且提供了增加和获取ViewModel的方法,以及清空HashMap和所有ViewModel的方法。结合它们名字中的Store。

我们不难推测:

  • ViewModelStoreOwner就是ViewModelStore持有者;
  • ViewModelStore是用来存储ViewModel的。

然后根据上文中创建ViewModel的代码:ViewModelProvider(this).get(CustomModel::class.java)。可以肯定的是,我们的Activity一定实现了ViewModelStoreOwner接口。

回看我们的Activity,它的继承关系如下图:

最终,可以在ComponentActivity里看到它实现了ViewModelStoreOwner接口。并且,还实现了HasDefaultViewModelProviderFactory接口。

///...
private ViewModelStore mViewModelStore;
///...
public ViewModelStore getViewModelStore() {
    ///...
    ensureViewModelStore();
    return mViewModelStore;
}

///...
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

上面的代码就是从ComponentActivity提取的关键代码,它涵盖ViewModel的创建和获取,并且确保了ViewModelStore实例的唯一性。我们的Activity通过继承即可实现对ViewModelStore的持有和管理,并间接控制所有ViewModel。

ViewModel实例的获取

在上文中讲的ViewModelStoreOwner和ViewModelStore都只是前置任务,真正的创建在get方法中:

ViewModelProvider.get(Class modelClas)的代码如下:

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);
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ///第二步
    ViewModel viewModel = mViewModelStore.get(key);

    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.
        }
    }
    ///第三步
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
    } else {
        viewModel = mFactory.create(modelClass);
    }
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}


代码中有关键的三步:

  • 第一步:根据类名创建Key值;
  • 第二步:检查ViewModelStore里是否有当前类型的ViewModel的实例,有就直接返回实例;
  • 第三步:如果ViewModelStore没有当前类型的实例,那么创建新的实例,将其加入到ViewModelStore中并返回实例对象。

可以看到,ViewModel的创建就是在第三步完成的。 同时在这里,上文中的ViewModelStore开始发挥作用了。正是通过ViewModelStore,我们的Activity才实现了对ViewModel的持有,同时,使用一个HaspMap的数据结构,通过类名做Key值,确保了同一类型的ViewModel的唯一性。也就是:在同一个Activity内,同一类型的ViewModel实例只会被实例化一次,即:只会有一个实例,在Fragment中也是如此。

Factory和真正的创建

在上一小节中,我们发现:ViewModel的实例是通过Factory创建的。Factoty是ViewModelProvider中的一个接口:

public interface Factory {
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

代码很简单,只有一个create方法。也就是ViewModel创建的地方。这个有点类似抽象工厂模式啊。 在开篇的基本使用中,我们讲过点构造参数的ViewModel的初始化。那里我们直接实现了一个Factory又来创建实例。这里不再赘述。我们只看一下ViewModelProvider(ViewModelStoreOwner)函数(也就是上文中ViewModelProvider的构造方法一)获取实例中的Factory从何而来:

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

Factory的来源有两个: 如果ViewModelStoreOwner没有实现HasDefaultViewModelProviderFactory接口,则使用NewInstanceFactory。其代码如下:

public static class NewInstanceFactory implements Factory {
    private static NewInstanceFactory sInstance;
 
    @NonNull
    static NewInstanceFactory getInstance() {
        if (sInstance == null) {
            sInstance = new NewInstanceFactory();
        }
        return sInstance;
    }

    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);
        }
    }
}

代码没什么复杂的:

  • 采用静态单例模式确保单例;
  • 实现了Factory接口,在create方法中通过反射获取Viewmodel实例

接下来看一下如果ViewModelStoreOwner实现HasDefaultViewModelProviderFactory接口的情况: HasDefaultViewModelProviderFactory源码很简单,只顶一个了一个获取Factory实例的方法:

public interface HasDefaultViewModelProviderFactory {
    @NonNull
    ViewModelProvider.Factory getDefaultViewModelProviderFactory();
}

HasDefaultViewModelProviderFactory有众多实现,我们只看一下ComponentActivity中的实现作为参考:

public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
    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;
}

可以看到,里面也是创建了一个SavedStateViewModelFactory,其中SavedStateViewModelFactory的父类实现了Factory接口,具体实现这里不再叙述了。

ViewModel的销毁

上文中详细讲述了ViewModel的创建,以及ViewModel是如何与Activity产生关系的。接下来,我们看下ViewModel是如何被销毁的。这里涉及到Lifecycle的知识点,不展开详细讲述了。 还记得上文中我们的Activity的继承关系吗?它的父类中有个FragmentActivity。在FragmentActivity中的onDestroy方法,向一个LifecycleRegistry发送了当前Activity的生命周期。代码如下:

@Override
protected void onDestroy() {
    super.onDestroy();
    mFragments.dispatchDestroy();
    mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}

继续追踪LifecycleRegistry,其关键代码如下:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    
    moveToState(event.getTargetState());
}

private void moveToState(State next) {
    sync();
}

private void sync() {
    while (!isSynced()) {
        
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            backwardPass(lifecycleOwner);
        };
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}

private void forwardPass(LifecycleOwner lifecycleOwner) {
            observer.dispatchEvent(lifecycleOwner, event);

}
private void backwardPass(LifecycleOwner lifecycleOwner) {
              observer.dispatchEvent(lifecycleOwner, event);
 }

void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = event.getTargetState();
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
  }

省去其中的各种细节,FragmentActivity通知的LifecycleRegistry 生命周期发生变化,LifecycleRegistry会低啊用LifecycleEventObserveronStateChanged方法。而LifecycleEventObserver是一个接口,仅有 onStateChanged一个方法。在ComponentActivity的构造方法中,使用匿名内部类的方式实现了这个接口:

getLifecycle().addObserver(new LifecycleEventObserver() {
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            // Clear out the available context
            mContextAwareHelper.clearAvailableContext();
            // And clear the ViewModelStore
            if (!isChangingConfigurations()) {
                getViewModelStore().clear();
            }
        }
    }
});

看到这个实现,销毁方法付出水面。正对应我们上文中所说的ViewModelStore的clear方法。

不难发现:ViewModel的生命周期是通过Lifecycle与Activity绑定的。每当activity销毁时,onDestory方法就会通过Lifecycle调用ViewModelStore的clear方法,从而达到销毁ViewModel的目的

总结

本文主要讲解了ViewModel的相关源码和基本使用。着重介绍了它的创建、销毁以及和Activity生命周期的绑定。其实ViewModel本身的源码很简单。在库中只有几个文件:

而且每个文件最多不过寥寥百行代码。让ViewModel发挥出它真正的威力,离不开JetPack其他组件的配合和支持。文中的Lifecycle就是一个典型的例子。配合LiveData、Room以及Kotlin的协程,能大幅提升开发的销量,提升你的代码质量。

举报

相关推荐

0 条评论