Android ViewTreeObserver不';不要叫onGlobalLayout

Android ViewTreeObserver不';不要叫onGlobalLayout,android,layout,Android,Layout,我已经有了使用ViewTreeObserver的活动,但在这种情况下,我没有得到onGlobalLayout回调 由于我在执行http API调用后获得了视图的宽度,因此宽度似乎已经计算过了(由于API调用所需的时间)。无论如何,为了确保将侦听器添加到ViewTreeObserver。但有时我没有收到回电(是的,有时) 我可以在添加侦听器之前检查宽度,以避免等待回调,但我不知道为什么有时无法获得回调。我已检查viewTreeObserver是否始终处于活动状态 ViewTreeObserver

我已经有了使用
ViewTreeObserver
的活动,但在这种情况下,我没有得到
onGlobalLayout
回调

由于我在执行http API调用后获得了视图的宽度,因此宽度似乎已经计算过了(由于API调用所需的时间)。无论如何,为了确保将侦听器添加到
ViewTreeObserver
。但有时我没有收到回电(是的,有时)

我可以在添加侦听器之前检查宽度,以避免等待回调,但我不知道为什么有时无法获得回调。我已检查
viewTreeObserver
是否始终处于活动状态

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();

assert viewTreeObserver.isAlive();

viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout()   // Not called sometimes, why?
    {
        view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        doSomething(view.getWidth());
    }
});
现在我将使用以下技巧:

int width = view.getWidth();

if (width > 0) {
    doSomething(view.getWidth());
} else {
    // use the ViewTreeObserver
}

编辑

为了以防万一,我制作了以下助手方法:

/**
 * Runs code on global layout event, useful when we need to do something after the layout is done
 * (like getting the view real measure). The runnable is only called once at most.
 *
 * A typical `shouldRun` function can be `v -> v.getWidth() > 0` since it checks that the view has some width,
 * so we can calculate things depending on that.
 *
 * @param shouldRun receives the `view` and decides if the runnable should run (it is checked when this method is called, and also on global layout).
 *
 * See: http://stackoverflow.com/questions/35443681/viewtreeobserver-doesnt-call-ongloballayout
 */
public static void runOnGlobalLayout(final View view, final Func1<View,Boolean> shouldRun, final Runnable runnable)
{
    if (shouldRun.call(view)) {
        runnable.run();
        return;
    }

    final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();

    if (viewTreeObserver.isAlive()) {
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (shouldRun.call(view)) {
                    view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    runnable.run();
                }
            }
        });
    }
}

从关于
ViewTreeObserver.OnGlobalLayoutListener
的官方文档中:

全局布局状态或视图树中视图的可见性更改时调用的回调的接口定义

如果http回调发生在视图(及其子视图)的最后一次可见性更改之后,则在
OnGlobalLayoutListener
中没有收到任何回调是正常的


当http请求在创建所有视图之前完成时,您将得到一个回调,因此您将在
onGlobalLayout
中得到一个回调,该回调涉及视图绘制的完成。

谢谢!你知道如何告诉Android:“嘿,你能告诉我这个视图什么时候计算了度量值吗?”@FerranMaylink是:viewWithGlobalListener.requestLayout()@FerranMaylink将手动重新计算度量值,这样它将进入onGlobalLayout回调。如果你已经完成了,请求另一个布局传递,你不觉得吗?有没有办法避免这种情况?而且。。。如果我一开始就收到了回调,请求布局会给我另一个回调,对吗?@FerranMaylinch是的,没错。如果只需要一个回调,则必须实现自定义逻辑
runOnGlobalLayout(someLayout, v -> v.getWidth() > 0, () -> {
    int availableWidth = someLayout.getWidth();
    // draw things in layout, etc.
});