https://github.com/open-android/Android
复习笔记
requestLayout和invalidate的区别
1.view不停找parent可以一直找到DecorView,按理说DecorView是顶点了,但是DecorView还有个虚拟父view,ViewRootImpl。 ViewRootImpl不是一个View或者ViewGroup,他有个成员mView是DecorView,所有的操作从ViewRootImpl开始自上而下分发
2.view的invalidate不会导致ViewRootImpl的invalidate被调用,而是递归调用父view的invalidateChildInParent,直到ViewRootImpl的invalidateChildInParent,然后触发peformTraversals,会导致当前view被重绘,由于mLayoutRequested为false,不会导致onMeasure和onLayout被调用,而OnDraw会被调用
3.一个view的invalidate会导致本身PFLAG_INVALIDATED置1,导致本身以及父族viewgroup的PFLAG_DRAWING_CACHE_VALID置0
4.requestLayout会直接递归调用父窗口的requestLayout,直到ViewRootImpl,然后触发peformTraversals,由于mLayoutRequested为true,会导致onMeasure和onLayout被调用。不一定会触发OnDraw
5.requestLayout触发onDraw可能是因为在在layout过程中发现l,t,r,b和以前不一样,那就会触发一次invalidate,所以触发了onDraw,也可能是因为别的原因导致mDirty非空(比如在跑动画)
6. requestLayout会导致自己以及父族view的PFLAG_FORCE_LAYOUT和PFLAG_INVALIDATED标志被设置。
7.一般来说,只要刷新的时候就调用invalidate,需要重新measure就调用requestLayout,后面再跟个invalidate(为了保证重绘),这是我个人的理解。
自定义view measure的几种测量模式
1. EXACTLY 精确值模式,当控件的layout_width和layout_height属性指定为具体数值或match_parent时。
1. AT_MOST 最大值模式,当空间的宽高设置为wrap_content时。
1. UNSPECIFIED 未指定模式,View想多大就多大,通常在绘制自定义View时才会用。
Handler原理,Handler/Looper/MessageQueue关系
主要是处理线程间通信。消息循环创建一个Looper循环并利用ThreadLOcal绑定到当前线程。
handler通过lopper向不同线程的handler发送消息
- Handler封装了消息的发送,也负责接收消。内部会跟Looper关联。
- Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理
- MessageQueue 就是一个消息队列,负责存储消息,有消息过来就存储起来,Looper会循环的从MessageQueue读取消息。(MessageQueue 底层使用的是单链表)
为什么一定要在ui线程更新ui
因为androiui 并不是线程安全的。线程安全: 所有操作同在固定同一个线程中完成。
handler同步屏障
设置了同步屏障之后,Handler只会处理异步消息。再换句话说,同步屏障为Handler消息机制增加了一种简单的优先级机制,异步消息的优先级要高于同步消息
衍生问题:一个线程可以有几个looper
只能有一个,不然调用looper.prepare()会跑出异常
一个线程可以有几个Handler
无数个,但looper只能有一个
Looper如何识别Handler?
handler会把属于自己的targert保存在message中。通过标示识别handler
handler类型的面试问题比较好的 。 https://juejin.im/post/5c6a9a106fb9a04a0c2f0093
android事件分发机制
事件分发的核心方法: dispatchTouchEvent() onTouchEvent() onInterceptTouchEvent()
传递顺序 activity => ViewGroup => View
SurfaceView双缓存机制
surfaceView的双缓存机制是处理游戏开发的重要技术。当动画在争先显示的时候,程序又在改变界面绘制,屏幕就会出现闪烁。
而双缓冲技术睡先把处理把事物在内存中处理好后再显示在界面上。先把要显示的东西处理好保存在内存中,再显示在屏幕上。
双缓冲机制分为前缓冲区和后缓冲区,前缓冲区处理的是正在渲染图形的缓冲区,后缓冲区是处理接下来要渲染的图形的缓冲区
multidex启动优化
- 编译时分包 将app中编译好的class分散在多个dex中
- 运行时,虚拟机只加载main dex中的class。启动后通过反射修改classload的方式加载其他的dex
tcp与udp笔记
TCP: 传输控制协议 是面向连接的协议。 必须确认建立的可靠的连接。需要进行三次握手确认 包头长度为最少20位
UDP: 无连接协议 包头长度为8位
典型例子 ping id
常见的排序算法
冒泡
/**
* 冒泡排序的第一种实现, 没有任何优化
* @param a
* @param n
*/
public static void bubbleSort1(int [] a, int n){
int i, j;
for(i=0; i<n; i++){//表示n次排序过程。
for(j=1; j<n-i; j++){
if(a[j-1] > a[j]){//前面的数字大于后面的数字就交换
//交换a[j-1]和a[j]
int temp;
temp = a[j-1];
a[j-1] = a[j];
a[j]=temp;
}
}
}
}
插入排序
public static void insertSort(int[] a) {
int i, j, insertNote;// 要插入的数据
for (i = 1; i < a.length; i++) {// 从数组的第二个元素开始循环将数组中的元素插入
insertNote = a[i];// 设置数组中的第2个元素为第一次循环要插入的数据
j = i - 1;
while (j >= 0 && insertNote < a[j]) {
a[j + 1] = a[j];// 如果要插入的元素小于第j个元素,就将第j个元素向后移动
j--;
}
a[j + 1] = insertNote;// 直到要插入的元素不小于第j个元素,将insertNote插入到数组中
}
}
快速排序
public static void sort(int a[], int low, int hight) {
int i, j, index;
if (low > hight) {
return;
}
i = low;
j = hight;
index = a[i]; // 用子表的第一个记录做基准
while (i < j) { // 从表的两端交替向中间扫描
while (i < j && a[j] >= index)
j--;
if (i < j)
a[i++] = a[j];// 用比基准小的记录替换低位记录
while (i < j && a[i] < index)
i++;
if (i < j) // 用比基准大的记录替换高位记录
a[j--] = a[i];
}
a[i] = index;// 将基准数值替换回 a[i]
sort(a, low, i - 1); // 对低子表进行递归排序
sort(a, i + 1, hight); // 对高子表进行递归排序
}