1、Retrofit的实现与原理
Retrofit是基于OkHttp,可以通过注解来配置请求方法的类型、请求参数、可以使用多种converter对数据进行解析,比如最常见的json、xml,并且支持rxjava,我觉得Retrofit中最核心的设计模式应该是动态代理,在利用构建者模式build出Retrofit对象后,一般直接调用retrofit的create(Class service)方法,service是个接口类,包装了访问服务器的方法, create方法中直接对service做了动态代理, 以后我们在调用service中的方法时,都会被代理,代理类中最主要的执行了三行代码
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
loadServiceMethod是将一个接口中的带注解的普通方法适配为一个http方法,这里会对method方法上的注解进行解析,包括baseurl、请求方法的类型(get、put)、请求参数等,然后利用serviceMethod构建了一个okHttpCall,这个类定义了一些同步、异步方法(就是真正要去请求网络的),然后第三部调用callAdapter的adapt方法,这个callAdapter方法是从adapterFactories集合中取的,就是在返回请求结果时做线程切换用的,如果在构建Retrofit时配置了rxjava,那么就是rxjava的,如果没有的话是从platform中取的,这个platform就是代表的Android,它也是利用了handler
new Handler(Looper.getMainLooper())
传递的是主线程的looper
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(final Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
这儿的callbackExecutor.execute其实就是执行的handler.post
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
2、HashMap、ConcurrentHashMap
HashMap的主干是一个存放Entry(键值对)的数组,数组的长度默认是16,HashMap中最常见的两个方法是get、put。在put一个Entry的时候,首先会根据key计算出一个哈希值,然后将这个Entry放到数组的对应位置上,如果这个位置上已经有值了,那么就会在该位置生成一个链表,新元素插入到该位置上,新元素的next指向旧元素,在get的时候,也是先计算出key的哈希值,然后去数组对应的位置上查找Entry,如果key不相等,顺着链表往后查找。
HashMap的默认长度是16,并且每次自动扩展或者手动初始化指定长度时也必须是2的幂,这样做的目的是为了实现一个尽量均匀分布的hash函数,HashMap的哈希算法采用了位运算符index = HashCode(Key) & (Length - 1),与2的幂次方减一进行&运算,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。
jdk1.8后HashMap的数据结构变为了数组+链表+红黑树,链表长度大于8时转换为红黑树
参考文章:https://blog.csdn.net/login_sonata/article/details/76598675
高并发情况:
https://blog.csdn.net/qfzhangwei/article/details/69938937
多线程put的时候可能导致元素丢失 、put非null元素后get出来的却是null
1.8以下,假设一个HashMap已经到了Resize的临界点。此时有两个线程A和B,在同一时刻对HashMap进行Put操作,两个线程各自执行resize然后rehash可能导致环形链表的出现,再执行get操作的时候会出现死循环
1.8中没有这个问题了。
3、红黑树
参考文章https://www.cnblogs.com/CarpenterLee/p/5503882.html
TreeMap
4、类加载机制
类从被加载到虚拟机内存开始到卸载出内存为止,它的整个生命周期包括了7个阶段,加载、验证、准备、解析、初始化、使用、卸载
a.加载阶段:主要完成三件事
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流锁代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问接口。
b.验证阶段:
这一阶段的主要目的是为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
c.准备阶段:
准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间
d.解析阶段:
解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程
f.初始化阶段:
初始化阶段是类加载最后一个阶段,执行类构造器<client>方法
5、requestLayout,invalidate,postInvalidate区别与联系
- requestLayout
是请求重新布局,是对整个view树进行一次测量、布局、绘制,子View调用requestLayout方法,会标记(PFLAG_FORCE_LAYOUT)当前View及父容器,同时逐层向上提交,直到ViewRootImpl处理该事件,ViewRootImpl会调用三大流程,从measure开始,对于每一个含有标记位的view及其子View都会进行测量、布局、绘制。 - invalidate
当子View调用了invalidate方法后,会为该View添加一个标记位(PFLAG_DIRTY),同时不断向父容器请求刷新,父容器通过计算得出自身需要重绘的区域,直到传递到ViewRootImpl中,最终触发performTraversals方法,进行开始View树重绘流程(只绘制需要重绘的视图),由于没有添加measure和layout的标记位,因此measure、layout流程不会执行,而是直接从draw流程开始。 - postInvalidate
这个方法与invalidate方法的作用是一样的,都是使View树重绘,但两者的使用条件不同,postInvalidate是在非UI线程中调用,invalidate则是在UI线程中调用。
网友评论