• 首页
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案
目录

onMeasure() 为什么会执行多次

调用 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);

}

相关文章