2024年Android最新学Android必知:Jetpack核心组件,ViewModel的使用及原理解析(1),面试官怎么破冰

尾声

你不踏出去一步,永远不知道自己潜力有多大,千万别被这个社会套在我们身上的枷锁给捆住了,30岁我不怕,35岁我一样不怕,去做自己想做的事,为自己拼一把吧!不试试怎么知道你不行呢?

改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

// 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)打开新世界的大门。

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

}

没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就还在啊,也就避免了横竖屏切换时的数据丢失。

viewModelProvider.get(UserModel.class)

下面我们来到那句构建ViewModel代码的后半段,它是ViewModelProvider的get()方法,看看实现,其实很简单。

public T get(@NonNull Class 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 get(@NonNull String key, @NonNull Class modelClass) {
//先取缓存 有缓存则用缓存
ViewModel viewModel = mViewModelStore.get(key);

if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}

//无缓存 则重新通过mFactory构建
viewModel = mFactory.create(modelClass);
//缓存起来
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}

大体思路是利用一个key来缓存ViewModel,有缓存则用缓存的,没有则重新构建。构建时使用的factory是上面of()方法的那个factory。

ViewModelStore

上面多个地方用到了ViewModelStore,它其实就是一个普普通通的保存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) {
oldViewModel.onCleared();
}
}

final ViewModel get(String key) {
return mMap.get(key);
}

/**

  • Clears internal storage and notifies ViewModels that they are no longer used.
    */
    public final void clear() {
    for (ViewModel vm : mMap.values()) {
    vm.onCleared();
    }
    mMap.clear();
    }
    }

ViewModelStore有一个HashMap专门用于存储,普通吧。

下面看看何时调用的clear()。

ViewModel.onCleared() 资源回收

既然ViewModel是生命周期感知的,那么何时应该清理ViewModel呢?

我们来到FragmentActivity的onDestroy()方法,发现它是在这里清理的。

/**

  • Destroy all fragments.
    */
    @Override
    protected void onDestroy() {
    super.onDestroy();

if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

碎片化学习效果强太多。

[外链图片转存中…(img-Nlbw7CVG-1715675530190)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值