Який правильний порядок виклику методів суперкласу в методах onPause, onStop та onDestroy? і чому?


89

Я щойно переглядав сайт розробника Android, оновлюючи життєвий цикл діяльності, і в кожному прикладі коду є коментар поряд із методами суперкласу, який говорить: "Завжди викликати метод суперкласу спочатку".

Хоча це має сенс у напівциклі створення: onCreate, onStart і onResume, я трохи заплутаний щодо того, яка правильна процедура для напівцикла знищення: onPause, onStop, onDestroy.

Спочатку знищувати ресурси конкретного екземпляра, перш ніж знищувати ресурси суперкласу, від яких можуть залежати ресурси конкретного екземпляра, має сенс, а не навпаки. Але коментарі говорять про інше. Чого мені не вистачає?

Редагувати : Оскільки, здається, люди плутаються щодо намірів у питанні, я хочу знати, що з наведеного нижче є правильним? І ЧОМУ ?

1.Google пропонує

    @Override
    protected void onStop() {
      super.onStop();  // Always call the superclass method first

      //my implementation here
    }

2.Інший шлях

    @Override
    protected void onStop() {
       //my implementation here

       super.onStop();  
    }

1
Я в таборі два для методів відключення. Я перебуваю в таборі для методів запуску.
danny117

1
Це в основному суть. Просто не міг зрозуміти, як використання методу 1 для методів вимкнення мало сенс.
Anudeep Bulla

Відповіді:


107

Спочатку знищувати ресурси, специфічні для екземпляра, перед тим, як знищувати ресурси суперкласу, від яких можуть залежати ресурси, специфічні для екземпляра, а не навпаки. Але коментарі говорять про інше. Чого мені не вистачає?

На мою думку: жодної речі.

Ця відповідь від Марка (він же CommonsWare on SO) проливає світло на проблему: Посилання - Чи повинен виклик методу суперкласу бути першим твердженням? . Але тоді ви можете побачити такий коментар, що залишився до його відповіді:

Але чому офіційний документ каже: "Завжди спочатку викликати метод суперкласу" в onPause ()?

Назад до першого квадрата. Гаразд, давайте подивимось на це з іншого боку. Ми знаємо, що специфікація мови Java не визначає порядок, у якому super.overridenMethod()потрібно здійснювати виклик (або якщо виклик повинен здійснюватися взагалі).

У разі активності класу super.overridenMethod()потрібні та примусові виклики :

if (!mCalled) {
    throw new SuperNotCalledException(
        "Activity " + mComponent.toShortString() +
            " did not call through to super.onStop()");
}

mCalledвстановлено значення true у Activity.onStop().

Тепер єдина деталь, яка залишилась для обговорення, - це порядок.

I also know that both work

Звичайно. Подивіться на тіло методу для Activity.onPause ():

protected void onPause() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);

    // This is to invoke 
    // Application.ActivityLifecyleCallbacks.onActivityPaused(Activity)
    getApplication().dispatchActivityPaused(this);

    // The flag to enforce calling of this method
    mCalled = true;
}

Куди б ти не зателефонував super.onPause(), ти будеш добре. Activity.onStop () має подібне тіло методу. Але погляньте на Activity.onDestroy ():

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

Тут, впорядкування може , можливо , незалежно від того , в залежності від того, як ваша діяльність установки і виклику чиsuper.onDestroy() буде втручатися в коді , який слід.

Як останнє слово, Always call the superclass method firstсхоже , у заяви немає великих доказів, що підтверджують це. Гірше (для твердження) - те, що взятий такий код android.app.ListActivity:

public class ListActivity extends Activity {

    ....

    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRequestFocus);
        super.onDestroy();
    }
    ....    
}

І, з прикладу програми LunarLander, включеного в Android sdk:

public class LunarLander extends Activity {

    ....

    @Override
    protected void onPause() {
        mLunarView.getThread().pause(); // pause game when Activity pauses
        super.onPause();
    }
    ....
}

Короткий зміст та гідні згадки:

Користувач Філіп Шерд : надає сценарій, коли дзвінок super.onPause()потрібно відкласти у випадку, якщо діяльність почала використовуватись startActivityForResult(Intent). Встановлення результату за допомогою setResult(...) після super.onPause() не буде працювати. Пізніше він пояснює це в коментарях до своєї відповіді.

Користувач Шериф elKhatib : Пояснює, чому дозволити суперкласу ініціалізувати спочатку його ресурси та останнє знищувати його ресурси випливає з логіки:

Давайте розглянемо завантажену вами бібліотеку, яка має LocationActivity, що містить функцію getLocation (), яка забезпечує розташування. Швидше за все, для цієї діяльності потрібно буде ініціалізувати свої матеріали в onCreate (), що змусить вас викликати спочатку super.onCreate . Ви вже робите це, бо відчуваєте, що це має сенс. Тепер у своєму onDestroy ви вирішили зберегти місце розташування десь у SharedPreferences. Якщо ви спочатку викликаєте super.onDestroy, певною мірою, що getLocation поверне нульове значення після цього виклику, оскільки реалізація LocationActivity зводить нанівець значення розташування в onDestroy. Ідея полягає в тому, що ви не звинувачуєте в цьому, якщо це трапиться. Отже, ви зателефонуєте super.onDestroy наприкінці після того, як закінчите з власним onDestroy.

Далі він зазначає: якщо дочірній клас належним чином ізольований (з точки зору залежності від ресурсів) від батьківського класу, super.X()виклики не повинні дотримуватися будь-якої специфікації замовлення.

Див свою відповідь на цю сторінку , щоб прочитати сценарій , при якому розміщення super.onDestroy()виклику дійсно впливає на логіку програми.

З відповіді Марка :

Перевизначені вами методи, які є частиною створення компонентів (onCreate (), onStart (), onResume () тощо), вам слід прив'язати до суперкласу як перше твердження , щоб переконатися, що Android має шанс виконати свою роботу перед вами намагатися зробити щось, що залежить від виконаної роботи.

Перевизначені вами методи, які є частиною знищення компонентів (onPause (), onStop (), onDestroy () тощо), вам слід виконати свою роботу першим і, як останню річ, прив’язати до суперкласу . Таким чином, якщо Android очистить щось, від чого залежить ваша робота, ви спочатку зробите свою роботу.

Методи, які повертають щось інше, ніж void (onCreateOptionsMenu () тощо), іноді ви прив'язуєте до суперкласу в операторі return, припускаючи, що ви спеціально не робите щось, що вимагає примусового певного поверненого значення.

Все інше - наприклад, onActivityResult () - залежить від вас загалом. Я, як правило, прив'язуюся до суперкласу, але якщо у вас не виникають проблеми, ланцюжок пізніше повинен бути нормальним.

Боб Кернс із цієї теми :

Це хороший шаблон [(шаблон, який Марк пропонує вище)], але я знайшов деякі винятки. Наприклад, тема, яку я хотів застосувати до моєї PreferenceActivity, не набуде чинності, якщо я не поставлю її перед суперкласом onCreate ().

Користувач Стів Бенетт також звертає увагу на це:

Я знаю лише одну ситуацію, коли потрібен час супердзвінка. Якщо ви хочете змінити стандартну поведінку теми або дисплея та подібного в onCreate, ви повинні зробити це перед тим, як зателефонувати супер, щоб побачити ефект . В іншому випадку AFAIK немає різниці, коли ви це телефонуєте.

Користувач Суніл Мішра підтверджує, що замовлення (швидше за все) не грає ролі при виклику методів класу активності. Він також стверджує, що виклик методів суперкласу першим вважається найкращою практикою . Однак я не міг це підтвердити.

Користувач LOG_TAG : Пояснює, чому виклик конструктора суперкласу повинен бути перед усім іншим. На мою думку, це пояснення не додає запитуваному питанню.

Кінцева примітка : Довіряйте, але перевіряйте. Більшість відповідей на цій сторінці дотримуються цього підходу, щоб перевірити, чи Always call the superclass method firstмає твердження логічну підтримку. Як виявляється, ні; принаймні, не у випадку класу Activity. Як правило, слід прочитати вихідний код суперкласу, щоб визначити, чи є замовлення викликів методів супер необхідною.


2
Ого. Дякую за вказівники. І це, і відповіді @ Sherif дають важливий контекст. Якщо хтось із вас може підсумувати відповіді на цій сторінці, я б позначив це як прийняте. Будь ласка, включіть: 1. Відповіді на цій сторінці. 2. @ Відповідь Філіпа на цій сторінці 3. @ CommonsWare відповідь на цій сторінці 4. Цю дискусію я б хотів, але я не хочу бачити ваші чудові відповіді. Вітання та подяки
Anudeep Bulla

Привіт. Не могли б ви підвести підсумок, бачачи, що @Sherif не хоче?
Anudeep Bulla

@AnudeepBulla Привіт Анудіп, дай мені термін до завтра. Я додаю відповідний матеріал до своєї відповіді і залишу вам коментар тут.
Vikram

@AnudeepBulla Я додав резюме вище. Будь ласка, повідомте мене, якщо я щось пропустив.
Vikram

@Vikram - це TL; DR. що дзвінок onDestroyі onStopостанній є більш безпечним за замовчуванням, і що для onPauseречей може бути складніше в декількох випадках? Не могли б ви це додати спочатку? У мене було спокуса самостійно відредагувати відповідь, але я не впевнений, що це короткий зміст правильний.
Blaisorblade

13

Оскільки (ви кажете) має сенс спершу назвати super onCreate: подумайте.

Коли я хочу творити, Мій супер створює свої ресурси> Я створюю свої ресурси.

І навпаки: (сорт стека)

Коли я хочу знищити, я знищую свої ресурси> Мій супер знищує його ресурси.


У цьому сенсі це стосується будь-якої пари функцій (onCreate / onDestroy, onResume / onPause, onStart / onStop). Природно, onCreate створить ресурси, а onDestroy звільнить ці ресурси. До речі, той самий доказ стосується інших пар.

Давайте розглянемо завантажену вами бібліотеку, яка має LocationActivity, що містить функцію getLocation (), яка забезпечує розташування. Швидше за все, для цієї діяльності потрібно буде ініціалізувати свої матеріали в onCreate (), що змусить вас викликати спочатку super.onCreate. Ви вже робите це, бо відчуваєте, що це має сенс. Тепер у своєму onDestroy ви вирішили зберегти місце розташування десь у SharedPreferences. Якщо ви спочатку викликаєте super.onDestroy, певною мірою, що getLocation поверне нульове значення після цього виклику, оскільки реалізація LocationActivity зводить нанівець значення розташування в onDestroy. Ідея полягає в тому, що ви не звинувачуєте цього, якщо це трапиться. Тому ви зателефонуєте до super.onDestroy наприкінці після того, як закінчите з власним onDestroy. Сподіваюсь, це має певний сенс.

Якщо вищезазначене має сенс, вважайте, що в будь-який момент ми маємо діяльність, яка дотримується вищезазначеної концепції. Якщо я хочу продовжити цю діяльність, я, мабуть, почуватимуся так само і дотримуватимуться того самого порядку через той самий точний аргумент.

За індукцією будь-яка діяльність повинна робити те саме. Ось хороший абстрактний клас для занять, змушених дотримуватися наступних правил:

package mobi.sherif.base;

import android.app.Activity;
import android.os.Bundle;

public abstract class BaseActivity extends Activity {
    protected abstract void doCreate(Bundle savedInstanceState);
    protected abstract void doDestroy();
    protected abstract void doResume();
    protected abstract void doPause();
    protected abstract void doStart();
    protected abstract void doStop();
    protected abstract void doSaveInstanceState(Bundle outState);
    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doCreate(savedInstanceState);
    }
    @Override
    protected final void onDestroy() {
        doDestroy();
        super.onDestroy();
    }
    @Override
    protected final void onResume() {
        super.onResume();
        doResume();
    }
    @Override
    protected final void onPause() {
        doPause();
        super.onPause();
    }
    @Override
    protected final void onStop() {
        doStop();
        super.onStop();
    }
    @Override
    protected final void onStart() {
        super.onStart();
        doStart();
    }
    @Override
    protected final void onSaveInstanceState(Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }
}

Нарешті, що, якщо ваша діяльність під назвою AnudeepBullaActivityрозширює BaseActivity і пізніше, я хочу створити, SherifElKhatibActivityщо розширює вашу діяльність? У якому порядку слід викликати super.doфункції? Зрештою це одне і те ж.


Щодо вашого запитання:

Я думаю, що намір Google полягає в тому, щоб сказати нам: Будь ласка, телефонуйте супермережею незалежно від того, де. Як звичайну практику, звичайно, називайте це спочатку. Звичайно, у Google є найрозумніші інженери та розробники, тому вони, мабуть, добре зробили, ізолюючи свої супер дзвінки та не втручаючись у дзвінки дитини.

Я трохи спробував, і, мабуть, непросто (оскільки ми намагаємося довести, що помиляємося в Google), створити таку діяльність, яка б просто збилася через те, коли викликається супер.

Чому?

Все, що робиться в цих функціях, насправді є приватним для класу Activity і ніколи не призведе до конфлікту з вашим підкласом. Наприклад (onDestroy)

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

mManagedCursors та mManagedDialogs та mSearchManager - це всі приватні поля. І жоден із загальнодоступних / захищених API не буде зачеплений тим, що робиться тут.

Однак в API 14 було додано dispatchActivityDestroyed для відправки onActivityDestroyed до ActivityLifecycleCallbacks, зареєстрованого у вашому додатку. Таким чином, будь-який код, який залежатиме від певної логіки у ActivityLifecycleCallbacks, матиме різні результати залежно від того, коли ви телефонуєте супер. Наприклад:

Створіть клас програми, який підраховує кількість поточно виконуваних дій:

package mobi.shush;

import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

public class SherifApplication extends Application implements ActivityLifecycleCallbacks {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
    }
    public int getCount() {
        return count;
    }
    int count = 0;
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        count++;
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
        count--;
    }
    @Override
    public void onActivityPaused(Activity activity) {}
    @Override
    public void onActivityResumed(Activity activity) {}
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState)           {}
    @Override
    public void onActivityStarted(Activity activity) {}
    @Override
    public void onActivityStopped(Activity activity) {}
}

Наведене нижче може не мати сенсу або не стосується належної практики, але це лише доведення аргументу (можна знайти більш реальну ситуацію). Створіть MainActivity, яка нібито переходить до активності GoodBye, коли вона закінчена і коли вона є останньою:

@Override
protected void onDestroy() {
    super.onDestroy();
    if(((SherifApplication) getApplication()).getCount() == 0) {
        //i want to go to a certain activity when there are no other activities
        startActivity(new Intent(this, GoodBye.class));
    }
}

Якщо ви зателефонуєте super.onDestroy на початку свого onDestroy, буде запущено діяльність GoodBye. Якщо ви зателефонуєте super.onDestroy в кінці свого onDestroy, діяльність GoodBye не буде запущена.

Звичайно, знову ж таки, це не оптимальний приклад. Однак це показує, що Google тут трохи зіпсувався. Будь-яка інша змінна не вплине на поведінку вашого додатка. Однак додавання цієї відправки до onDestroy призвело до того, що супер якось заважав вашому підкласу.

Я кажу, що вони зіпсувались і з іншої причини. Вони не тільки (до 14 квітня) лише зачіпали у супервикликах те, що є остаточним та / або приватним, але вони також називали різні внутрішні функції (приватні), які насправді відправляли функції onPause ....

Наприклад, performStopфункція - це функція, яка викликається, що, у свою чергу, викликає функцію onStop:

final void performStop() {
    if (mLoadersStarted) {
        mLoadersStarted = false;
        if (mLoaderManager != null) {
            if (!mChangingConfigurations) {
                mLoaderManager.doStop();
            } else {
                mLoaderManager.doRetain();
            }
        }
    }

    if (!mStopped) {
        if (mWindow != null) {
            mWindow.closeAllPanels();
        }

        if (mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
        }

        mFragments.dispatchStop();

        mCalled = false;
        mInstrumentation.callActivityOnStop(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onStop()");
        }

        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (!mc.mReleased) {
                    mc.mCursor.deactivate();
                    mc.mReleased = true;
                }
            }
        }

        mStopped = true;
    }
    mResumed = false;
}

Зверніть увагу, що вони викликають Activity's onStop десь у цій функції. Тому вони могли б також розмістити весь код (включений у super.onStop) до або після виклику onStop, а потім просто повідомити підкласи про onStop, використовуючи порожні супер функції SuperStop, і навіть не додаючи SuperNotCalledException або перевіряючи це.

Для цього, якби вони викликали цю диспетчерику до ActivityLifeCycle у perforDestroy, замість того, щоб викликати її в кінці super.onDestroy, поведінка нашої діяльності була б однаковою незалежно від того, коли ми називали супер.

У будь-якому випадку це перше, що вони роблять (трохи неправильно), і це лише в API 14.


Ніколи не виникало питання, чому дзвінок super.onDestroy () востаннє має сенс. Мені подобається твій бібліотечний приклад. Саме те, що я теж хотів передати. Я не міг домовитись більше про виклик супер методів останнім на останніх півцикла знищення, точно як у стеку; щоб запобігти випадковій втраті даних. Проблема полягає в тому, чому Google наполягає на перших викликах суперметодів, враховуючи вищезазначену передумову? Я поставив запитання, тому що думав, що, можливо, я, і, здавалося б, і ви теж, можливо, підходите до нього зовсім інакше. Вітання
Анудіп Булла

О, я не бачив, як Google пропонує та інший шлях: p! Слухайте, я спробую створити таку діяльність, яка зазнає краху, якщо ви спочатку зателефонуєте наDestroy. Вам слід спробувати і це. Привітання
шериф elKhatib

@AnudeepBulla, ти можеш перевірити мої правки. І до речі, ви можете перестати намагатися. super.onймовірно ніколи не призведе до збою вашої активності.
Sherif elKhatib

Ого. Дякую за вказівники. І це, і відповіді @ User надають важливий контекст. Якщо хтось із вас може підсумувати відповіді на цій сторінці, я б позначив це як прийняте. Будь ласка, включіть: 1. Відповіді на цій сторінці. 2. @ Відповідь Філіпа на цій сторінці 3. @ CommonsWare відповідь на цій сторінці 4. Цю дискусію я б хотів, але я не хочу бачити ваші чудові відповіді. Вітання та подяки
Anudeep Bulla

@AnudeepBulla Ласкаво просимо. Я не впевнений, як ми будемо вирішувати, хто опублікує остаточний запис.
Vikram

2

Ви говорите, що Google пропонує метод 1, проте Діанн Хакборн, відомий інженер фреймворків Android, пропонує інше переглянути посилання на форум Google .

Це має інтуїтивний сенс називати супер клас останнім при знищенні екземпляра в методах onPause, onStop та onDestroy і спочатку при створенні екземпляра з методами onCreate, onResume та onStart .


Посилання на допис Діанни Хакборн є важливим і підтверджує закономірність.
Нік Вестгейт

1

З точки зору Java, ось якесь рішення для цієї плутанини:

Чому this () та super () повинні бути першим твердженням у конструкторі?

Конструктор батьківського класу потрібно викликати перед конструктором підкласу. Це гарантуватиме, що якщо ви викликаєте будь-які методи батьківського класу у своєму конструкторі, батьківський клас уже налаштований правильно.

Те, що ви намагаєтесь зробити, передати args супер конструктору цілком законно, вам просто потрібно побудувати ці args вбудовано, як ви робите, або передати їх своєму конструктору, а потім передати super:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                super(myArray);
        }
}

Якщо компілятор не застосував цього, ви можете зробити це:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                someMethodOnSuper(); //ERROR super not yet constructed
                super(myArray);
        }
}

Це показує, що насправді, підполя повинні бути ініціалізовані перед надкласом! Тим часом вимога Java "захищає" нас від спеціалізації класу, спеціалізуючи те, що аргументує суперконструктор

У випадках, коли батьківський клас має конструктор за замовчуванням, виклик super вставляється автоматично для вас компілятором. Оскільки кожен клас у Java успадковується від Object, конструктор об'єктів повинен бути якось викликаний, і його потрібно виконати спочатку. Автоматична вставка супер () компілятором це дозволяє. Примушуючи супер з’являтися першим, доводиться до того, що тіла конструктора виконуються в правильному порядку: Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth

(1) Перевірки того, що супер є першим твердженням, недостатньо для запобігання цій проблемі. Наприклад, ви можете поставити "super (someMethodInSuper ());" у вашому конструкторі. Це намагається отримати доступ до методу в суперкласі до його побудови, хоча super є першим оператором.

(2) Здається, компілятор реалізує іншу перевірку, яка сама по собі є достатньою для запобігання цій проблемі. Повідомлення "не може посилатися на xxx до того, як був викликаний конструктор супертипу". Тому перевіряти, чи є супер першим твердженням, не потрібно

Будь ласка, пройдіть цей http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html


Я прекрасно розумію, що ви там викладаєте. Спочатку ви викликаєте конструктори супер класу, тому що вони можуть ініціалізувати ресурси, які можуть знадобитися дитині; а деструктори тривають, 'бо ти не хочеш, мабуть, стирати всіх батьків з місцевих ресурсів, роблячи їх безглуздими. Це точно моя суть. І оскільки onPause, onStop і onDestroy мають завдання зберігати інформацію про стан і більш-менш робити ресурси доступними для GC (тому в певному сенсі їх руйнуючи), я бачу їх аналогічними деструкторам, і тому вважаю, що називати їх останнім має сенс. Немає?
Anudeep Bulla

Все, що ви сказали вище, - це саме те, що я мав на увазі, коли сказав, що "виклик суперметодів спочатку має сенс у напівциклі створення". Я стурбований і збентежений у випадку методів знищення циклу, які здаються більш аналогічними деструкторам. Вітання
Анудіп Булла

1

Найголовніше, про що слід пам’ятати, це super.onPause()неявні дзвінки setResult(Activity.RESULT_CANCELED). Але setResultможна викликати лише один раз, а всі наступні дзвінки ігноруються. Отже, якщо ви хочете повернути будь-який результат назад до батьківської діяльності, вам слід зателефонувати setResultсамому собі, перш ніж телефонувати super.onPause(). Наскільки мені відомо, це найбільша проблема.


Ого, це здається важливим. Тож виникає ситуація, коли вам точно доведеться відкласти виклик супер методів. Дякую.
Anudeep Bulla

super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Не могли б ви сказати, звідки ви це взяли?
Vikram

Я розгубився. Це насправді END (), який викликає setResult, а super.onBackPress () виклики finish (). Тож setResult однозначно потрібно викликати перед super.onBackPress (). Я не впевнений, чи існують якісь обставини, за яких super.onPause () може викликати виклик setResult, але я волію не ризикувати.
Філіп Ширд,

1

І правильні IMO

Згідно з документами

Похідні класи повинні викликати реалізацію цього методу в суперкласі. Якщо цього не сталося, буде створено виняток.

Super завжди слід викликати метод, коли в документації явно про це сказано.

Однак ви можете вибрати, коли викликати супер метод.

Дивлячись на джерело onPause

protected void onPause() {
    getApplication().dispatchActivityPaused(this);
    mCalled = true;
}

Отже, незалежно від того, до чого або після цього воно не називається. Ви повинні бути хорошими.

Але для найкращої практики спочатку слід зателефонувати їй.

Я рекомендую його здебільшого як механізм захисту: якщо є виняток, то superметод екземпляру вже буде викликаний.

Також розміщення цих викликів на першому рядку допоможе вам уникнути помилок у майбутньому, таких як видалення коду в методі та випадкове видалення виклику до суперкласу.


Вибачте, якщо питання було не зовсім зрозумілим вперше, але будь ласка, погляньте на нього зараз.
Anudeep Bulla

@AnudeepBulla Ось що я вам пояснив. Ви можете використовувати будь-який з них. Обидва є дійсними.
Суніл Мішра,

Я розумію, що користувацька реалізація методів onPause, onStop та onDestroy не є суворо необхідною. Я робив безліч додатків без них. То що ви маєте на увазі під методами Супер завжди слід називати? Вони називаються неявно, навіть без перевизначення. Я також знаю, що обидва працюють. Я хочу знати, чому в документах сказано, що супер слід назвати першим. І у випадку, якщо питання все ще не очевидне, чи можете ви пояснити, ЧОМУ, коли ви говорите "Але для найкращої практики спочатку слід зателефонувати до неї"?
Anudeep Bulla

Якщо ви не перевизначаєте, викликаються методи, Base Classале якщо ви перевизначаєте, вам потрібно викликати superінше, що у вас будеandroid.app.SuperNotCalledException
Sunil Mishra

1
Здається, ви не зрозуміли. Питання не в тому, телефонувати чи ні. Як ви вже вказали, ви МОЖЕТЕ, якщо ви їх заміните. Питання в тому, коли?
Anudeep Bulla

0

Супер зворотних дзвінків потрібен, щоб внутрішньо перевести Діяльність у правильний стан для системи.

Скажімо, ви починаєте свою діяльність, і система викликає onCreate. Тепер ви можете його замінити і, наприклад, завантажити ваш макет. Але задля системного потоку вам потрібно зателефонувати супер, щоб система могла продовжувати стандартну процедуру. Ось чому буде вилучено виняток, якщо ви його не назвете.

Це відбувається незалежно від вашої реалізації в onCreate. Це лише важливе значення для системи. Якби не було ANR, ви могли б мати нескінченний цикл у будь-якому зворотному виклику, і Activity буде потрапляти в цей. Отже, система знає, коли зворотний виклик був припинений, і чим дзвонить наступний.

Я знаю лише одну ситуацію, коли потрібен час супердзвінка. Якщо ви хочете змінити стандартну поведінку теми або дисплея та подібного в onCreate, ви повинні зробити це перед тим, як зателефонувати супер, щоб побачити ефект. В іншому випадку AFAIK немає різниці, коли ви телефонуєте.

Але щоб система зробила те, що вона найкраще може поставити супер у перший рядок зворотного виклику, за яким слідує ваш код, якщо у вас немає вагомих причин перервати його.


Послідовність у onCreate здається майже зрозумілою. Що відбувається в методах знищення? Скажіть onStop. Припустимо, моя реалізація onStop використовує деякі ресурси, які випускає метод super, якщо їх викликати. Тоді має сенс викликати метод super після моєї реалізації.
Anudeep Bulla

В ідеалі, це має бути так, правильно. Наша діяльність завжди матиме ресурси, які є у суперкласу, а також деякі інші. А ті, які не залежать від моєї діяльності, можуть, в більшості випадків, залежати від загальноприйнятих ресурсів суперкласу. Більше сенсу мати справу з моїми ресурсами, а потім закликати суперклас мати справу із загальними. Чому тоді Google каже, що ми «ПОВИННІ» спочатку викликати методи суперкласу?
Anudeep Bulla

Про який ресурс ви говорите, до якого ви можете отримати доступ у onCreate, але не в onDestroy?
Steve Benett

У мене немає випадку використання. Мені просто цікаво, як це залежить від стилю ООП. Конструктори суперкласів називаються першими, до вашої реалізації, а деструктори супер класів називаються останніми, після вашої реалізації, чи не так? onPause, onStop і onDestroy не є строго деструкторами, але вони, як правило, роблять однакові речі, так? Щонайменше onDestroy і в основному onStop теж .. ні?
Anudeep Bulla

Зверніть увагу на зворотні виклики у стані, що змінюється, а не як конструктор / деструктор. Кожен зворотний виклик має необхідність, наприклад, створити (готовий до використання) / знищити (ваш останній шанс взаємодії) діяльність або поставити її на передній план / фон. Зворотні дзвінки є там, за допомогою яких ви можете контролювати свої ресурси в потоці системи. Система просто перевіряє, в якому стані вона знаходиться, і обробляє відповідно. Ресурси, які ви використовуєте, та той, який система контролює, незалежні один від одного, і перетину не буде.
Steve Benett
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.