ViewModel 使用及原理解析,在线面试app

  1. 这时候在Activity中就可以使用ViewModel了. 其实就是一句代码简单实例化,然后就可以使用ViewModel了.

//这些东西我是引入的androidx下面的

import androidx.fragment.app.FragmentActivity;

import androidx.lifecycle.Observer;

import androidx.lifecycle.ViewModelProviders;

public class MainActivity extends FragmentActivity {

private TextView mContentTv;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mContentTv = findViewById(R.id.tv_content);

//构建ViewModel实例

final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);

//让TextView观察ViewModel中数据的变化,并实时展示

userModel.mUserLiveData.observe(this, new Observer() {

@Override

public void onChanged(User user) {

mContentTv.setText(user.toString());

}

});

findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

//点击按钮 更新User数据 观察TextView变化

userModel.doSomething();

}

});

}

}

这个时候,我们点击一下按钮(user中的age变为15),我们可以旋转手机屏幕(这个时候其实Activity是重新创建了,也就是onCreate()方法被再次调用,但是ViewModel其实是没有重新创建的,还是之前那个ViewModel),但是当我们旋转之后,发现TextView上显示的age居然还是15,这就是ViewModel的魔性所在.这个就不得不提ViewModel的生命周期了,它只有在Activity销毁之后,它才会自动销毁(所以别让ViewModel持有Activity引用啊,会内存泄露的). 下面引用一下谷歌官方的图片,将ViewModel的生命周期展示的淋漓尽致.

3. ViewModel妙用1: Activity与Fragment"通信"

有了ViewModel,Activity与Fragment可以共享一个ViewModel,因为Fragment是依附在Activity上的,在实例化ViewModel时将该Activity传入ViewModelProviders,它会给你一个该Activity已创建好了的ViewModel,这个Fragment可以方便的访问该ViewModel中的数据.在Activity中修改userModel数据后,该Fragment就能拿到更新后的数据.

public class MyFragment extends Fragment {

public void onStart() {

//这里拿到的ViewModel实例,其实是和Activity中创建的是一个实例

UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);

}

}

4. ViewModel妙用2: Fragment与Fragment"通信"

下面我们来看一个例子(Google官方例子)

public class SharedViewModel extends ViewModel {

private final MutableLiveData selected = new MutableLiveData();

public void select(Item item) {

selected.setValue(item);

}

public LiveData getSelected() {

return selected;

}

}

public class MasterFragment extends Fragment {

private SharedViewModel model;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

itemSelector.setOnClickListener(item -> {

model.select(item);

});

}

}

public class DetailFragment extends Fragment {

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

model.getSelected().observe(this, { item ->

// Update the UI.

});

}

}

  1. 首先定义一个ViewModel,在里面放点数据

  2. 然后在MasterFragment和DetailFragment都可以拿到该ViewModel,拿到了该ViewModel就可以拿到里面的数据了,相当于间接通过ViewModel通信了. so easy…

二、ViewModel源码解析

又到了我们熟悉的源码解析环节

我们从下面这句代码start.

final UserModel userModel = ViewModelProviders.of(this).get(UserModel.class);

我们跟着ViewModelProviders.of(this)打开新世界的大门

1. ViewModelProviders.of(this) 方法

/**

  • 用于构建一个ViewModelProvider,当Activity是alive时它会保留所有的该Activity对应的ViewModels.

*/

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity) {

return of(activity, null);

}

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity,

@Nullable Factory factory) {

//检查application是否为空,不为空则接收

Application application = checkApplication(activity);

if (factory == null) {

//构建一个ViewModelProvider.AndroidViewModelFactory

factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);

}

return new ViewModelProvider(activity.getViewModelStore(), factory);

}

ViewModelProviders里面的of()函数其实是为了方便我们构建一个ViewModelProvider.而ViewModelProvider,一看名字就知道干啥的了,就是提供ViewModel的.

Factory是ViewModelProvider的一个内部接口,它的实现类是拿来构建ViewModel实例的.它里面只有一个方法,就是创建一个ViewModel.

/**

  • Implementations of {@code Factory} interface are responsible to instantiate ViewModels.

*/

public interface Factory {

/**

  • Creates a new instance of the given {@code Class}.

  • @param modelClass a {@code Class} whose instance is requested

  • @param The type parameter for the ViewModel.

  • @return a newly created ViewModel

*/

@NonNull

T create(@NonNull Class modelClass);

}

Factory有2个实现类:一个是NewInstanceFactory, 一个是AndroidViewModelFactory .

  • NewInstanceFactory源码

public static class NewInstanceFactory implements Factory {

@SuppressWarnings(“ClassNewInstance”)

@NonNull

@Override

public T create(@NonNull Class 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);

}

}

}

NewInstanceFactory专门用来实例化那种构造方法里面没有参数的class,并且ViewModel里面是不带Context的,然后它是通过newInstance()去实例化的.

  • AndroidViewModelFactory 源码

public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

private static AndroidViewModelFactory sInstance;

/**

  • Retrieve a singleton instance of AndroidViewModelFactory.

  • @param application an application to pass in {@link AndroidViewModel}

  • @return A valid {@link AndroidViewModelFactory}

*/

@NonNull

public static AndroidViewModelFactory getInstance(@NonNull Application application) {

if (sInstance == null) {

sInstance = new AndroidViewModelFactory(application);

}

return sInstance;

}

private Application mApplication;

/**

  • Creates a {@code AndroidViewModelFactory}

  • @param application an application to pass in {@link AndroidViewModel}

*/

public AndroidViewModelFactory(@NonNull Application application) {

mApplication = application;

}

@NonNull

@Override

public T create(@NonNull Class modelClass) {

if (AndroidViewModel.class.isAssignableFrom(modelClass)) {

//noinspection TryWithIdenticalCatches

try {

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

}

}

AndroidViewModelFactory专门用来实例化那种构造方法里面有参数的class,并且ViewModel里面可能是带Context的.

  • 它是通过newInstance(application)去实例化的.如果有带application参数则是这样实例化

  • 如果没有带application参数的话,则还是会走newInstance()方法去构建实例.

AndroidViewModelFactory通过构造方法给ViewModel带入Application,就可以在ViewModel里面拿到Context,因为Application是APP全局的,那么不存在内存泄露的问题.完美解决了有些ViewModel里面需要Context引用,但是又担心内存泄露的问题.

下面我们继续ViewModelProviders.of(this)方法继续分析吧,注意最后一句new ViewModelProvider(activity.getViewModelStore(), factory);第一个参数会调用activity的getViewModelStore()方法(这个方法会返回ViewModelStore,这个类是拿来存储ViewModel的,下面会说到),这里的activity是androidx.fragment.app.FragmentActivity,看一下这个getViewModelStore()方法

/**

  • 获取这个Activity相关联的ViewModelStore

*/

@NonNull

@Override

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;

}

//没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore

//注意,这是FragmentActivity中的NonConfigurationInstances(其实Activity中还定义了一个NonConfigurationInstances,内容要比这个多一些,但是由于没有关系到它,这里就不提及了)

static final class NonConfigurationInstances {

Object custom;

ViewModelStore viewModelStore;

FragmentManagerNonConfig fragments;

}

Android横竖屏切换时会触发onSaveInstanceState(),而还原时会调用onRestoreInstanceState(),但是Android的Activity类还有2个方法名为onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()这两个方法。

来具体看看这2个素未谋面的方法

/**

保留所有fragment的状态。你不能自己覆写它!如果要保留自己的状态,请使用onRetainCustomNonConfigurationInstance()

这个方法在FragmentActivity里面

*/

@Override

public final Object onRetainNonConfigurationInstance() {

Object custom = onRetainCustomNonConfigurationInstance();

FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

if (fragments == null && mViewModelStore == null && custom == null) {

return null;

}

NonConfigurationInstances nci = new NonConfigurationInstances();

nci.custom = custom;

nci.viewModelStore = mViewModelStore;

nci.fragments = fragments;

return nci;

}

//这个方法在Activity里面,而mLastNonConfigurationInstances.activity实际就是就是上面方法中年的nci

public Object getLastNonConfigurationInstance() {

return mLastNonConfigurationInstances != null

? mLastNonConfigurationInstances.activity : null;

}

我们来看看getLastNonConfigurationInstance()的调用时机,

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {

mViewModelStore = nc.viewModelStore;

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!

Android架构师之路很漫长,一起共勉吧!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
blog.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-f17jJsSs-1712814465235)]

最后

现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!

Android架构师之路很漫长,一起共勉吧!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-U4OAIeaQ-1712814465236)]

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值