LeakCanary
LeakCanary用于监控Activity/Fragment是否发生内存泄漏。一般来说Activty销毁的时候,也就是调用onDestory后,垃圾回收时Activty对象必须被回收,没有的话就说明发生了内存泄漏。LeakCanary是怎样检测某个Activity是否发生内存泄漏的呢?Application中有个方法registerActivityLifecycleCallbacks(),用于监听Activity的生命周期。当监听到Activity调用onDestroy()的时候,通过一个弱引用保存当前Activity对象,并传入一个ReferenceQueue 。引用队列的作用是当引用指向的对象被垃圾回收时,会把引用放入到引用队列中。如果没有放进去,则说明发生了内存泄漏。LeakCanary接着会生成内存快照,并进行分析,找到GC Roots到Activity的引用路径,然后以发送通知的形式告知客户结果。
Java内存问题 及 LeakCanary 原理分析
LeakCanary原理浅析
BlockCanary
BlockCanary — 轻松找出Android App界面卡顿元凶
性能优化(7.3)-BlockCanary原理分析
Retrofit
注解+反射+动态代理
- 概括
1、Retrofit就是一个网络请求框架的封装,底层的网络请求默认使用的Okhttp,本身只是简化了用户网络请求的参数配置等,还能与Rxjava相结合,使用起来更加简洁方便。
2、App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,之后由OkHttp完成后续的请求操作。
3、在服务端返回数据之后,OkHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
4、完成数据的转化(converterFactory),适配(callAdapterFactory),通过设计模式进行各种扩展。 - 使用
@GET("/user/{user}/repos")
Call> listRepos(@Path("user") String user);
//call封装了整个okhttp的请求
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverteractory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//converterFactory
//后续交个okhttp
https://www.jianshu.com/p/0c055ad46b6c
https://www.jianshu.com/p/a6aea82c2fed
https://www.jianshu.com/p/491603d9fadc
Okhttp
- Dispather
maxRequests = 64 // 最大并发请求数为64
maxRequestsPerHost = 5 //每个主机最大请求数为5
ExecutorService executorService //消费者池(也就是线程池)
Deque readyAsyncCalls: // 异步的缓存,正在准备被消费的(用数组实现,可自动扩容,无大小限制)
Deque runningAsyncCalls //正在运行的 异步的任务集合,仅仅是用来引用正在运行的任务以判断并发量,注意它并不是消费者缓存
Deque runningSyncCalls //正在运行的,同步的任务集合。仅仅是用来引用正在运行的同步任务以判断并发量
okHttp有两种调用方式,一种是阻塞的同步调用,一种是非阻塞的异步调用,都需要Dispather来进行调度。
Dispather底层维护了一个线程池(缓存线程池,核心线程为0,阻塞队列容量为0,即是提交一个任务就新开一个线程执行,保证不会长时间阻塞),三个队列(一个队列存放正在运行的同步任务,一个存放正在运行的异步任务,一个存放准备运行的异步任务)
执行同步请求时,把任务插进队列;异步请求时,判断是否正在执行的线程是否超过64,超过则插进准备运行的队列等待执行,不超过则插进正在运行的队列直接执行。
https://www.jianshu.com/p/074dff0f4ecb
- 拦截器、责任链
Okhttp的核心是拦截器,每个拦截器都是对请求和响应进行各自的处理,多个拦截器形成责任链,责任链的运行模式是:每个拦截器拿到上一个拦截器的请求,处理后交给下一个拦截器;拿到下一个拦截器的响应,处理之后返回给上一个拦截器,实现分层处理。
https://www.jianshu.com/p/d9e85968c97f - 缓存策略
1 缓存的实现:第一个请求网络后把响应缓存起来,响应头中有缓存的标识,下一次发起请求把缓存表示发送到服务器,服务器比对后通知客户端缓存是否失效,失效则返回结果码200,不失效返回304。
缓存标识有2组:
(1)响应头中的Last-Modified,表示服务器中该资源的最后修改时间,下次请求时把请求头中If-Modified-Since中的值设为Last-Modified的值,服务器比对时间后返回不同的响应码。
(2)响应头中的 ETag,表示资源ID。下次请求时把该ID放到请求头中,服务器比对ID,不同则说明资源改过,返回200,相同则返回304。
2、 Okhttp的缓存策略是:
(1)没有网络,且没有缓存,返回错误。
(2)没有网络,有缓存则返回缓存。
(3)有网络连接,没有缓存/缓存过期,则返回网络的请求结果。
(4)有网络有缓存,则看情况而定。 - Okhttp使用DiskLruCache进行磁盘缓存
https://www.jianshu.com/p/b32d13655be7
Gilde的缓存机制
Glide的缓存机制包括内存缓存和硬盘缓存。
获取图片时先从内存缓存获取,获取不到再去硬盘缓存中获取,获取不到则从网络中获取,从网络中获取到图片后先设置到硬盘缓存中,再设置到内存缓存。
内存缓存又分为2级:弱引用缓存和LruCache
从内存缓存中获取图片时,先从LruCache中获取,拿到则把Lrucache中的图片删除并放到弱引用缓存中,Lrucache中拿不到则从弱引用缓存中获取。
把图片放到内存缓存中时,则是先放到弱引用缓存中,图片不再使用才放进LruCache中。
总结:弱引用缓存放的是正在使用的图片,LruCache放的是不在使用的图片,目的是什么?暂时还没想清楚
硬盘缓存由于可以设置缓存原图还是处理后的图片,也可以都缓存,默认是缓存处理后的图片,所以硬盘缓存也有2级缓存。
默认情况下Glide会优先从获取处理后的图片,不存在要读取的图片时,才会去读取原始图片。
把图片放进硬盘缓存则是先判断是否允许缓存原始图片,允许就先缓存原始图片,再缓存转换后的图片。
https://www.jianshu.com/p/7b1ff697b06f
https://blog.csdn.net/guolin_blog/article/details/54895665
Eventbus
- 使用
1 // 注册订阅者
EventBus.getDefault().register(this);
2 //处理订阅事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
...
}
3 //发送事件
EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
- 原理
订阅逻辑 :
1、首先用register()方法注册一个订阅者
2、获取该订阅者的所有订阅的方法
3、根据该订阅者的所有订阅的事件类型,将订阅者存入到每个以 事件类型为key 以所有订阅者为values的map集合中
4、然后将订阅事件添加到以订阅者为key 以订阅者所有订阅事件为values的map集合中
4.1、如果是订阅了粘滞事件的订阅者,从粘滞事件缓存区获取之前发送过的粘滞事件,响应这些粘滞事件。
事件发送逻辑 :
1、首先获取当前线程的事件队列
2、将要发送的事件添加到事件队列中
3、根据发送事件类型获取所有的订阅者
4、根据响应方法的执行模式,在相应线程通过反射执行订阅者的订阅方法
https://blog.csdn.net/u012317510/article/details/78935720
https://www.cnblogs.com/all88/archive/2016/03/30/5338412.html
https://www.jianshu.com/p/f057c460c77e
ButterKnife
- 使用
1//注解
@BindView(R.id.content)
FrameLayout mContent;
2//Activity Oncreate中调用
ButterKnife.bind(this);
- 原理
1:实现注解模块,编译时注解(Retention = CLASS),作用于变量(target = field)。
2: 实现注解解释器:继承AbstractProcessor,重写process()方法。
process()方法主要是实现的功能:收集注释信息(哪些类中使用了注解、类中注解修饰的哪些类,注解中的值等),生成代理类的java代码。
import com.zhy.ioc.*;
public class MainActivity$$ViewInjector implements ViewInjector{
@Override
public void inject(com.zhy.sample.MainActivity host , Object object ){
if(object instanceof android.app.Activity){
host.mTv = (android.widget.TextView)(((android.app.Activity)object).findViewById(2131492945));
}
else{
host.mTv = (android.widget.TextView)(((android.view.View)object).findViewById(2131492945));
}
}
}
3:编写api
api底层实现是:通过反射调用相关类的的bind方法。
public static void inject(Object host , Object root){
Class> clazz = host.getClass();
String proxyClassFullName = clazz.getName()+"$$ViewInjector";
//省略try,catch相关代码
Class> proxyClazz = Class.forName(proxyClassFullName);
ViewInjector viewInjector = (com.zhy.ioc.ViewInjector) proxyClazz.newInstance();
viewInjector.inject(host,root);
}
https://blog.csdn.net/lmj623565791/article/details/51931859
https://blog.csdn.net/u010405231/article/details/52210466
https://blog.csdn.net/ta893115871/article/details/52497297
https://blog.csdn.net/lmj623565791/article/details/43452969