1.1 谈一谈LeakCanray的工作原理?
LeakCanary 主要利用了弱引用的对象,当 GC 回收了这个对象后,会被放进 ReferenceQueue 中;
在页面消失,也就是 activity.onDestroy 的时候, 判断利用idleHandler发送一条延时消息,5秒之后,分析 ReferenceQueue 中存在的引用,如果当前 activity 仍在引用队列中,则认为可能存在泄漏,再利用系统类 VMDebug 提供的方法,获取内存快照,找出 GC roots 的最短强引用路径,并确定是否是泄露, 如果泄漏,建立导致泄露的引用链;
System.runFinalization(); // 强制调用已经失去引用的对象的 finalize 方法
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
// 1.. 从 retainedKeys 移除掉已经被会回收的弱引用
removeWeaklyReachableReferences();
// 3.. 若当前引用不在 retainedKeys, 说明不存在内存泄漏
if (gone(reference)) {
return DONE;
}
// 4.. 触发一次gc
gcTrigger.runGc();
// 5.. 再次从 retainedKeys 移除掉已经被会回收的弱引用
removeWeaklyReachableReferences();
if (!gone(reference)) {
// 存在内存泄漏
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
// 获得内存快照
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
.referenceName(reference.name)
.watchDurationMs(watchDurationMs)
.gcDurationMs(gcDurationMs)
.heapDumpDurationMs(heapDumpDurationMs)
.build();
heapdumpListener.analyze(heapDump);
}
return DONE;
}
1.2 谈一谈EventBus的原理?
1、 register方法将对象实例用软引用包裹,保存到一个map缓存集合中
2、post方法 传入一个对象进去,然后遍历map里面多有的对象,找到所有的带有 @subscribe注解的并且方法参数与post的对象是同一类型的Method, 并通过反射执行Method
3、Subscribe线程调度 执行method方法的时候会去获取注解上标记得线程,然后切换到指定线程
4、unregister取消订阅 从第一步中的缓存map中移除对应注册的对象实例
1.3 谈谈网络请求中的拦截器(Interceptor)?
系统自带的拦截器:
1,重试和重定向
2,请求头+响应头处理
3,缓存
4,dns + 三次握手
5,CallServer,读写数据流常用的自定义拦截器:
1,日志拦截器
2,自定义缓存规则拦截器
3,重试机制等等
1.4 谈一谈Glide的缓存机制?
- Glide的缓存机制,主要分为2种缓存,一种是内存缓存,一种是磁盘缓存。
- 使用内存缓存的原因是:防止应用重复将图片读入到内存,造成内存资源浪费。
- 使用磁盘缓存的原因是:防止应用重复的从网络或者其他地方下载和读取数据。
具体来讲,缓存分为加载和存储:
- 当加载一张图片的时候,获取顺序:Lru算法缓存-》弱引用缓存-》磁盘缓存(如果设置了的话)。
当想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,并将该图片放入WeakReference中,如果LruCache中没有,则去WeakReference中寻找,如果WeakReference中有,则从WeakReference中取出图片使用,如果WeakReference中也没有图片,则从磁盘缓存/网络中加载图片。 - 将缓存图片的时候,写入顺序:弱引用缓存-》Lru算法缓存-》磁盘缓存中。
当图片不存在的时候,先从网络下载图片,然后将图片存入弱引用中,glide会采用一个acquired(int)变量用来记录图片被引用的次数, 当acquired变量大于0的时候,说明图片正在使用中,也就是将图片放到弱引用缓存当中;如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用方法来释放资源,首先会将缓存图片从弱引用中移除,然后再将它put到LruResourceCache当中。
这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。
另:从Glide4.x开始,读取图片的顺序有所改变:弱引用缓存-》Lru算法缓存-》磁盘缓存
1.5 ViewModel的出现是为了解决什么问题?并简要说说它的内部原理?
viewModel出现为了解决什么问题?
看下viewModel的优点就知道了:
- 对于activity/fragment的销毁重建,它们内部的数据也会销毁,通常可以onSaveInstanceState()方法保存,通过onCreate的bundle中重新获取,但是大量的数据不合适,而vm会再页面销毁时自动保存并在页面加载时恢复。
- 对于异步获取数据,大多时候会在页面destroyed时回收资源,随着数据和资源的复杂,会造成页面中的回收操作越来越多,页面处理ui的同时还要处理资源和数据的管理。而引入vm后可以把资源和数据的处理统一放在vm里,页面回收时系统也会回收vm。加上databinding的支持后,会大幅度分担ui层的负担。
内部原理:
vm内部很简单,只有一个onClean方法。
vm的创建一般是这样ViewModelProviders.of(getActivity()).get(UserModel.class);
- ViewModelProviders.of(getActivity())
在of方法中通过传入的activity获取构造一个HolderFragment,HolderFragment内有个ViewModelStore,而ViewModelStore内部的一个hashMap保存着系统构造的vm对象,HolderFragment可以感知到传入页面的生命周期(跟glide的做法差不多),HolderFragment构造方法中设置了setRetainInstance(true),所以页面销毁后vm可以正常保存。 - get(UserModel.class);
获取ViewModelStore.hashMap中的vm,第一次为空会走创建逻辑,如果我们没有提供vm创建的Factory,使用我们传入的activity获取application创建AndroidViewModelFactory,内部使用反射创建我们需要的vm对象。
1.6 请说说依赖注入框架ButterKnife的实现原理?
- 通过注解器在编译期间生成一个XX_ViewBinding.java文件(XX可以是activity,fragment,adapter,dialog),这个文件
这么生成的?
注解器里会添加需要类型的注解;
查找XX类中的特定类型注解,如果有,拼接成字符串,创建并写到XX_ViewBinding.java文件中 - XX_ViewBinding.java会持有XX的引用,如果是初始化控件,通过xx.findViewById实现如果是设置监听,类似xx.setOnClickListener实现
- XX类中初始化XX_ViewBinding对象,这样打通了整个流程
1.7 谈一谈RxJava背压原理?
总共分为4种策略
- BackpressureStrategy.ERROR:若上游发送事件速度超出下游处理事件能力,且事件缓存池已满,则抛出异常//阻塞时队列
- BackpressureStrategy.BUFFER:若上游发送事件速度超出下游处理能力,则把事件存储起来等待下游处理
- BackpressureStrategy.DROP:若上游发送事件速度超出下游处理能力,事件缓存池满了后将之后发送的事件丢弃
- BackpressureStrategy.LATEST:若上有发送时间速度超出下游处理能力,则只存储最新的128个事件
网友评论