OnGlobalLayoutListener: застарілість та сумісність


75

Мені потрібно використовувати 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

Чи можу я проігнорувати їх, якщо я повинен якось виправити?

Відповіді:


142

Я використовую це у своєму проекті:

@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 EDIT Цей підхід дуже застарів. Сподіваюся, ви перенесли свій код до Котліна. Тепер ми можемо використовувати функцію doOnPreDraw при використанні бібліотеки ktx. https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#(android.view.View).doOnPreDraw(kotlin.Function1)


На початку я використав ваш код, але він видає помилку (для виклику потрібен рівень API 16 (поточний хв - 8): android.view.ViewTreeObserver # removeOnGlobalLayoutListener) і попередження (метод removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListenerO) із типу View ViewTistereeO) застарілий). Мій код вирішує ці проблеми, але дає попередження LogCat
— crbin1

попередження добре. це тому, що ви використовуєте jar якоїсь версії sdk із застарілою функцією для пристроїв <sdk. так що ви все ще можете ним користуватися.
— Уді Оші,

9
@ crbin1 ви можете додати @TargetApi (Build.VERSION_CODES.JELLY_BEAN) перед оголошенням функції, якщо ви хочете уникати бачення цього попередження / помилки.
— розробник android

7
Google, це жахливо.
— Олівер Діксон,

39

Я вважаю, що правильним є використання Build.VERSION.SDK_INTі 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);
            }
}

1
Думаю, ви хочете передати слухача removeGlobalLayoutListenerзамістьthis
— Серхіо Серра

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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.