OnGlobalLayoutListener:弃用和兼容性

76

我必须使用一个 OnGlobalLayoutListener 对象,然后移除监听器,我遇到了一些已经过时的方法问题,我用下面的代码解决了这个问题。

protected void onCreate(Bundle savedInstanceState) {
    final LinearLayout llTotal = (LinearLayout) findViewById(R.id.mmc_ll);
    ViewTreeObserver vto = llTotal.getViewTreeObserver();
    if(vto.isAlive()){
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //
                // mycode
                //
                if (Build.VERSION.SDK_INT<16) {
                    removeLayoutListenerPre16(llTotal.getViewTreeObserver(),this);
                } else {
                    removeLayoutListenerPost16(llTotal.getViewTreeObserver(), this);
                }
            } 
        });
    }
    super.onCreate(savedInstanceState);
}

@SuppressWarnings("deprecation")
private void removeLayoutListenerPre16(ViewTreeObserver observer, OnGlobalLayoutListener listener){
    observer.removeGlobalOnLayoutListener(listener);
}

@TargetApi(16)
private void removeLayoutListenerPost16(ViewTreeObserver observer, OnGlobalLayoutListener listener){
    observer.removeOnGlobalLayoutListener(listener);
}

这是否正确?有没有更好的处理兼容性的方法?

在使用API 10的模拟器中运行代码时,LogCat中会出现以下警告:

04-24 09:30:12.565: I/dalvikvm(471): Could not find method android.view.ViewTreeObserver.removeOnGlobalLayoutListener, referenced from method com.my.project.ActivityHome.removeLayoutListenerPost16
04-24 09:30:12.565: W/dalvikvm(471): VFY: unable to resolve virtual method 2950: Landroid/view/ViewTreeObserver;.removeOnGlobalLayoutListener (Landroid/view/ViewTreeObserver$OnGlobalLayoutListener;)V

如果我需要修复,那我可以忽略它们吗?

5个回答

146

我在我的项目中使用这个:

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
    if (Build.VERSION.SDK_INT < 16) {
        v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
    } else {
        v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
    }
}

看起来和你的很相似。在不同设备上测试过(4.2.2和2.3.3),运行得很完美。似乎这是唯一的办法......如果你找到其他方式,我想知道。

2020年编辑 这种方法已经非常非常过时了。我希望你将代码迁移到Kotlin。现在,当使用ktx库时,我们可以使用doOnPreDraw函数。 https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#(android.view.View).doOnPreDraw(kotlin.Function1)


一开始我使用了你的代码,但是它出现了一个错误(需要API级别16(当前最低级别为8):android.view.ViewTreeObserver#removeOnGlobalLayoutListener),还有一个警告(类型ViewTreeObserver的removeGlobalOnLayoutListener(ViewTreeObserver.OnGlobalLayoutListener)方法已过时)。我的代码解决了这些问题,但是给出了LogCat警告。 - crbin1
警告没关系。这是因为您正在使用某个SDK版本的JAR文件,其中包含对低于该SDK版本的设备已弃用的函数。因此,您仍然可以使用它。 - Udi Oshi
9
如果你希望避免看到这个警告/错误信息,你可以在函数声明前添加 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)。 - android developer
7
谷歌,这太糟糕了。 - Oliver Dixon

39

我认为正确的方法是使用Build.VERSION.SDK_INTBuild.VERSION_CODES

public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
            } else {
                v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
            }
}

1
我认为你想将监听器传递给 removeGlobalLayoutListener 而不是 this - Sergio Serra

10
    mView.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
                //noinspection deprecation
                mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
            //
            // mycode
            //
        } 
    });

9
当然,检查Android版本并调用正确的方法更加谨慎,但如果你查看Android源代码,你会发现一些有趣的东西:
 @Deprecated
    public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
        removeOnGlobalLayoutListener(victim);
    }

这段代码是从API 18中剪切出来的。


6
根据文档:docs

此方法已在API级别16中弃用。使用#removeOnGlobalLayoutListener代替

非常有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接