OnGlobalLayoutListener: deprecation and compatibility
Asked Answered
A

5

77

I have to use an OnGlobalLayoutListener object and then to remove the listener, I had a problem with deprecated methods that I resolve with following code.

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);
}

Is it correct? There is a better way to handle compatibility?

Running the code in emulator with API 10 I have the following warning in 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

Can I ignore them of I have to fix in some way?

Addend answered 24/4, 2013 at 10:23 Comment(0)
H
146

I'm using this in my project:

@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);
    }
}

looks similar to yours. Tested on different devices (4.2.2 & 2.3.3) and it run perfectly. seems like it's the only way....If you find anything else I would like to know it. good luck

2020 EDIT This approach is very very obsolete. I hope you moved your code to Kotlin. Now we can use doOnPreDraw function when using ktx library. https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#(android.view.View).doOnPreDraw(kotlin.Function1)

Hexameter answered 24/4, 2013 at 11:4 Comment(4)
At the beginning I used your code but it give an error (Call requires API level 16 (current min is 8): android.view.ViewTreeObserver#removeOnGlobalLayoutListener) and a Warning (The method removeGlobalOnLayoutListener(ViewTreeObserver.OnGlobalLayoutListener) from the type ViewTreeObserver is deprecated). My code resolve those issues but give the LogCat warningAddend
warning is fine. it's because you're using jar of some sdk version with deprecated function for devices < sdk. so you can still use it.Hexameter
@Addend you can add @TargetApi(Build.VERSION_CODES.JELLY_BEAN) before the function declaration , if you wish to avoid seeing this warning/error.Osher
Google, this is horrible.Kaciekacy
K
39

I think the correct way is using Build.VERSION.SDK_INT and Build.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);
            }
}
Kab answered 19/5, 2014 at 15:20 Comment(1)
I think you want to pass the listener to removeGlobalLayoutListener instead of thisBreaststroke
B
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
            //
        } 
    });
Barm answered 1/12, 2016 at 6:32 Comment(0)
M
9

Of course that check the Android version and call the correct method is much more prudent, but if you take a look on the Android source code you can see something interesting:

 @Deprecated
    public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
        removeOnGlobalLayoutListener(victim);
    }

This code was snipped from API 18

Meissen answered 7/10, 2013 at 1:54 Comment(0)
G
6

According to the docs:

This method was deprecated in API level 16. Use #removeOnGlobalLayoutListener instead

Works like a charm.

Ghat answered 12/10, 2016 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.