调用 addView、setVisbility、setTextView时,onMeasure就会被调用多次。因为调用 addView、setVisbility、setTextView等都会调用 requestLayout,而调用 requestLayout就会执行 view的 绘制流程,也就是说会执行 performMeasure、performLayout、performDraw,就会执行 onMeasure。为了防止卡顿、提高性能和效率,要慎用 addView等。
一、onMeasure() 为什么会执行多次
调用 addView、setVisbility、setTextView时,onMeasure就会被调用多次
因为调用 addView、setVisbility、setTextView等都会调用 requestLayout,而调用 requestLayout就会执行 view的 绘制流程,也就是说会执行 performMeasure、performLayout、performDraw,就会执行 onMeasure;
所以为了防止卡顿、提高性能和效率,要慎用 addView、setVisbility、setTextView等方法,因为这几个方法会重新调用 requestLayout,会重新测量、重新摆放、重新绘制view,影响性能。
RootView需要添加到Window里才能展示,但是Window并不是直接管理RootView,而是通过ViewRootImpl进行管理。那么Window与RootView又是什么关系?
你可能已经发现了,addToDisplay(xx)并没有传入RootView,那么RootView是如何添加到Window里呢?
实际上,这里的添加说法比较拟人化。
在relayoutWindow(xx)里,传入了mSurfaceControl,返回后就与Surface mSurface 建立了联系。也就是说底层的Surface与Java 层的Surface关联起来了。而通过Surface,能够拿到Canvas。而每个View的绘制都需要关联Canvas,以此类推,View就与Surface关联了,那么在View上进行的绘制都会反馈到Surface上。这也就是说View添加到了Window。
延伸阅读:
二、iOS 各个线程 Autorelease 对象的内存管理
- Autoreleasepool 与 Runloop 的关系
- ARC 下什么样的对象由 Autoreleasepool 管理
- 子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理?不手动处理会内存泄漏吗?
针对名列前茅个问题,比较容易理解,可以看一下:ibireme 的 深入理解RunLoop,主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,并进行Push、Pop 等操作来进行内存管理
第二个问题,ARC 下什么样的对象由 Autoreleasepool 管理呢?大多数人的回答是:“都会由 pool 进行管理”。其实并不是这样的,对于普通的对象是由编译器在合适的地方为我们 Realease 了。针对这个问题,我已经总结过:引用计数带来的一次讨论,是参考了经典的《iOS与OS X多线程和内存管理 》这本书。
针对第三个问题,感觉比较难以回答,需要很细致的读过 Runtime 、Autoreleasepool 的源码才可以。我也是参考了 StackOverFlow 的回答:does NSThread create autoreleasepool automatically now?does NSThread create autoreleasepool automaticly now?。我再来简单阐述下,在子线程你创建了 Pool 的话,产生的 Autorelease 对象就会交给 pool 去管理。如果你没有创建 Pool ,但是产生了 Autorelease 对象,就会调用 autoreleaseNoPage 方法。在这个方法中,会自动帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的 AutoreleasePoolPage,如果你还是不理解,可以先看看 Autoreleasepool 的源代码,再来看这个问题 ),并调用page->add(obj)将对象添加到 AutoreleasePoolPage 的栈中,也就是说你不进行手动的内存管理,也不会内存泄漏啦!StackOverFlow 的作者也说道,这个是 OS X 10.9+和 iOS 7+ 才加入的特性。并且苹果没有对应的官方文档阐述此事,但是你可以通过源码了解。这里张贴部分源代码:
static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
// No pool in place.
// hotPage 可以理解为当前正在使用的 AutoreleasePoolPage。
assert(!hotPage());
// POOL_SENTINEL 只是 nil 的别名
if (obj != POOL_SENTINEL && DebugMissingPools) {
// We are pushing an object with no pool in place,
// and no-pool debugging was requested by environment.
_objc_inform(“MISSING POOLS: Object %p of class %s “
“autoreleased with no pool in place – “
“just leaking – break on “
“objc_autoreleaseNoPool() to debug”,
(void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
// Install the first page.
// 帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的 AutoreleasePoolPage
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push an autorelease pool boundary if it wasn’t already requested.
// POOL_SENTINEL 只是 nil 的别名,哨兵对象
if (obj != POOL_SENTINEL) {
page->add(POOL_SENTINEL);
}
// Push the requested object.
// 把对象添加到 自动释放池 进行管理
return page->add(obj);
}