【问题标题】:Does posting Runnable to an UI thread guarantee that layout is finished when it is run?将 Runnable 发布到 UI 线程是否保证布局在运行时完成?
【发布时间】:2014-02-21 14:32:33
【问题描述】:

第一件事!我确实知道ViewTreeObserver.onGlobalLayoutListener

让我问这个问题的是 Android 开发者文档网站上的以下通知:

下面的 sn-p 做了以下事情:

  • 获取父视图并在 UI 线程上发布 Runnable。 这可确保父级在调用 getHitRect() 方法。 getHitRect() 方法获取孩子的命中 父坐标中的矩形(可触摸区域)。

片段本身是:

parentView.post(new Runnable() {
            // Post in the parent's message queue to make sure the parent
            // lays out its children before you call getHitRect()
            @Override
            public void run() {
               /// do UI stuff
            }
});

(可以看full article

那么这是一个错误的陈述还是真的? 我之所以问,是因为与使用 ViewTreeObserver 进行所有注册侦听器/处理事件/取消注册侦听器舞蹈相比,发布可运行文件似乎更容易、更方便:)

更新:还有一个问题可以使整个主题更加清晰: 如果这一切都很好,并且 Runnable 实际上可以发布而不是使用全局布局侦听器,那么为什么我们还有这个 ViewTreeObserver.onGlobalLayoutListener 机制呢?什么时候使用它而不是发布 Runnable 更好,这些方法之间有什么区别?

【问题讨论】:

  • 使用Runnable,运行时你处于布局阶段之后
  • 很好的问题,并同意它比观察者更好。您可以通过在 onCreate() 中发布它来测试这一点,在 run() 中更改 UI 元素的布局,然后在发布后也更改相同的布局,也在 onCreate() 中。如果 runnable 确实在布局之后发生,您应该在 runnable 中看到布局更改,而不是 onCreate() 中的那个?????对“如何将两个数字相加”、“nullPointerException”和“为什么我会丢失 ; 符号语法错误”做出了很好的改变。
  • 这是我通常使用的方式。例如,如果我需要获取 View 的大小,我必须等到整个层次结构绘制完毕。所以我通常采用根布局并发布可运行文件。这样我就可以确定当我的 runnable 被执行时,布局至少已经被测量过了。
  • @Simon,是的,或者只是检查 UI 组件的 getWidth(),它不应该是 0 :)
  • @pskink,blackbelt 是的,似乎大部分时间都有效,但我很好奇某处是否有关于此的“官方”声明:)

标签: android multithreading android-layout


【解决方案1】:

我也喜欢这个问题。它迫使我再次深入研究 Android 源代码。我相信这是可行的,因为post()setContentView() 之后被调用。

方法setContentView()最终调用顶视图的ViewGroup.addView(),而addView()调用总是触发requestLayout()。反过来,requestLayout() 将任务发布到主线程以供稍后执行。此任务将在视图层次结构上执行测量和布局。现在,如果您发布另一个任务,它将被放入队列 after 布局任务,因此,总是执行 after 测量和布局发生。因此,您将始终拥有有效的尺寸。

【讨论】:

  • 哇,感谢您的参与!为了完整起见,您如何看待 - 当我在运行时将新构建的 View 添加到某些现有 ViewGroup 时会发生什么情况(假设在初始布局已经发生之后)。如果我在添加这个新视图后立即执行 post(...),那么视图是否已经在 Runnable.run() 中布局仍然成立?
  • 我很确定会是这样。第一个布局将发生,然后您的 Runnable 将被执行。
  • 另一个子问题:如果这一切都是好的和真实的,那么为什么我们有这个 ViewTreeObserver.onGlobalLayoutListener 机制呢?什么时候使用它而不是发布 Runnable 更好?我会更新这个问题,把这一切弄清楚很有趣:)
  • 我相信,如果您添加一个视图,那么您可以将一次性侦听器替换为已发布的可运行文件。但是如果你需要通知每个布局或者你需要另一种事件,你需要这个监听器。
  • 不,我的意思是如果 第一个布局发生在响应某些按钮单击时我会做 'myLayout.add(new View(...)); myLayout.post(Runnable)' - runnable 会布局视图吗?
猜你喜欢
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多