ViewTreeObserver 视图树观察者,当视图树进行测量,布局,焦点,绘制等情况时,视图树ViewTreeObserver都会收到通知,回调相应的方法。
这个对象不用我们自己实例化,直接从view中获取。
ViewTreeObserver observer = root.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int[] location = new int[2];
root.getLocationInWindow(location);
int[] location1 = new int[2];
root.getLocationOnScreen(location1);
Log.i(TAG, "locationX: " + location[0]);
Log.i(TAG, "locationY: " + location[1]);
Log.i(TAG, "location1X: " + location1[0]);
Log.i(TAG, "location1Y: " + location1[1]);
observer.removeOnGlobalLayoutListener(this);
}
});
这个有什么用呢,比如说我们要获取某一个控件的宽度,在onCreate方法是获取不到的,这个时候就可以用这个ViewTreeObserver这个视图观察者来搞了,等视图测量完或者布局完就可以拿宽高了。用完了记得remove掉这个视图。当然我们也可以在onResume中拿到这个宽高
其实他的内部是把你设置的listener都放到了一个个的list中(CopyOnWriteArrayList),每次回调都会遍历这个list然后回调其中的方法。
说道这个CopyOnWriteArrayList这个东西是写时复制容器。 我们使用ArrayList进行并发操作就可能会抛异常,使用CopyOnWriteArrayList就不会,因为他在写的时候进行了加锁,并对原来的元素进行一次copy,所以写的时候是在copy的元素上进行的写然后在将原来的元素指针指向这个copy的元素,所以对于并发来说不影响读,当然可能可能没有那么的即时。
public boolean add(E e) {
synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
}
}
其实这个鬼还有一个缺点就是占用内存,因为毕竟进行了一次copy。
这个东西适合并发情况下读多写少的场景,毕竟占用一个双倍的内存其实也是一个很大的问题的。
网友评论