Каков правильный порядок вызова методов суперкласса в методах 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 на SO) проливает свет на проблему: Ссылка - должен ли вызов метода суперкласса быть первым оператором? . Но затем вы можете увидеть следующий комментарий, оставленный к его ответу:

Но почему официальный документ говорит: «Всегда сначала вызывайте метод суперкласса» в onPause ()?

В начало. Хорошо, давайте посмотрим на это под другим углом. Мы знаем, что спецификация языка Java не определяет порядок, в котором super.overridenMethod()должен быть размещен вызов (или если вызов должен быть размещен вообще).

В случае класса Activity 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()должен быть отложен в случае начала использования Activity startActivityForResult(Intent). Установить результат с помощью setResult(...) after super.onPause() не получится. Позже он поясняет это в комментариях к своему ответу.

Пользователь Шериф elKhatib : Объясняет, почему разрешение суперклассу инициализировать его ресурсы первым и уничтожать его ресурсы последним следует из логики:

Давайте рассмотрим загруженную вами библиотеку, которая имеет LocationActivity, который содержит функцию getLocation (), которая определяет местоположение. Скорее всего, этому действию нужно будет инициализировать его содержимое в onCreate (), что заставит вас сначала вызвать super.onCreate . Вы уже делаете это, потому что чувствуете, что это имеет смысл. Теперь в своем onDestroy вы решаете, что хотите сохранить Location где-нибудь в 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, вы должны сделать это до того, как вызовете super, чтобы увидеть эффект . В противном случае, AFAIK, нет разницы, в какое время вы его вызываете.

Пользователь Сунил Мишра подтверждает, что порядок (скорее всего) не играет роли при вызове методов класса Activity. Он также утверждает, что сначала вызов методов суперкласса считается лучшей практикой . Однако я не мог подтвердить это.

Пользователь LOG_TAG : объясняет, почему вызов конструктора суперкласса должен быть перед всем остальным. На мой взгляд, это объяснение не добавляет к задаваемому вопросу.

Конец примечания : Доверяй, но проверяй. В большинстве ответов на этой странице используется этот подход, чтобы проверить, имеет ли утверждение Always call the superclass method firstлогическое обоснование. Как оказалось, это не так; по крайней мере, не в случае класса Activity. Как правило, следует прочитать исходный код суперкласса, чтобы определить, требуется ли упорядочивание вызовов методов super.

Викрам
источник
2
Вау. Спасибо за указатели. И этот, и ответ @ Sherif дают важный контекст. Если кто-либо из вас сможет обобщить ответы на этой странице, я бы отметил его как принятый. Пожалуйста, укажите: 1. Ответы на этой странице. 2. Ответ @ Philip на этой странице 3. Ответ @ CommonsWare на этой странице 4. Это обсуждение Я бы хотел, но мне не нужны кредиты за ваши замечательные ответы. Cheers & Thanks
Anudeep Bulla
Здравствуй. Не могли бы вы подвести итог, поскольку @Sherif не хочет?
Anudeep Bulla
@AnudeepBulla Привет, Anudeep, дай мне до завтра. Я добавлю соответствующий материал к своему ответу и оставлю вам здесь комментарий.
Vikram
@AnudeepBulla Я добавил резюме выше. Пожалуйста, дайте мне знать, если я что-то пропустил.
Викрам
@Vikram - это TL; DR. что вызов onDestroyи onStopпоследний - более безопасный вариант по умолчанию, и что onPauseв некоторых случаях может быть сложнее? Не могли бы вы добавить это первым? Мне хотелось отредактировать ответ самостоятельно, но я не уверен, что это резюме правильное.
Blaisorblade
13

Поскольку (вы говорите), имеет смысл сначала вызвать super onCreate: подумайте об этом.

Когда я хочу творить, Мой супер создает свои ресурсы> Я создаю свои ресурсы.

Наоборот: (своего рода стек)

Когда я хочу разрушить, я уничтожаю свои ресурсы> Мой супер уничтожает свои ресурсы.


В этом смысле это применимо к любой паре функций (onCreate / onDestroy, onResume / onPause, onStart / onStop). Естественно, onCreate создаст ресурсы, а onDestroy освободит эти ресурсы. Кстати, то же доказательство применимо и к другим парам.

Давайте рассмотрим загруженную вами библиотеку, которая имеет LocationActivity, который содержит функцию getLocation (), которая определяет местоположение. Скорее всего, для этого действия нужно будет инициализировать его содержимое в onCreate (), что заставит вас сначала вызвать super.onCreate. Вы уже делаете это, потому что чувствуете, что это имеет смысл. Теперь в своем onDestroy вы решаете, что хотите сохранить Location где-нибудь в 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);
    }
}

Наконец, что, если ваша активность под названием AnudeepBullaActivityextends BaseActivity, а позже, я хочу создать SherifElKhatibActivity, расширяет вашу активность? В каком порядке мне вызывать super.doфункции? В конечном итоге это одно и то же.


Что касается вашего вопроса:

Я думаю, что намерение Google состоит в том, чтобы сказать нам: пожалуйста, звоните суперу, где бы то ни было. В качестве общей практики, конечно, называйте это вначале. У Google, конечно же, самые блестящие инженеры и разработчики, поэтому они, вероятно, хорошо поработали, изолировав свои супервызовы и не вмешиваясь в дочерние вызовы.

Я немного попробовал, и, вероятно, непросто (поскольку мы пытаемся доказать, что ошибается Google) создать действие, которое просто вылетало из-за вызова When, super.

Зачем?

Все, что делается в этих функциях, действительно является частным для класса 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, будет иметь другой результат в зависимости от того, когда вы вызываете super. Например:

Создайте класс приложения, который подсчитывает количество выполняемых в данный момент действий:

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 привело к тому, что super каким-то образом помешал вашему подклассу.

Я говорю, что они напортачили и по другой причине. Они не только (до api 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;
}

Обратите внимание, что они вызывают onStop действия где-то в этой функции. Следовательно, они могли бы также поместить весь код (включенный в super.onStop) до или после вызова onStop, а затем просто уведомить подклассы об onStop, используя пустые суперфункции onStop и даже не добавляя SuperNotCalledException или проверяя это вызванное.

Для этого, если бы они вызвали эту отправку ActivityLifeCycle в performDestroy вместо того, чтобы вызывать ее в конце super.onDestroy, поведение нашей активности было бы таким же, независимо от того, когда мы действительно вызывали super.

Во всяком случае, это первое, что они делают (немного не так), и это только в API 14.

Шериф эль-Хатиб
источник
Вопрос никогда не заключался в том, почему имеет смысл вызывать super.onDestroy () последним. Мне нравится ваш пример из библиотеки. Именно то, что я хотел передать. Я не мог больше согласиться с вызовом суперметодов последними на последних полуциклах уничтожения, точно так же, как в стеке; чтобы предотвратить случайную потерю данных. Проблема в том, почему Google настаивает на первом вызове суперметодов, учитывая вышеизложенное? Я задал этот вопрос, потому что подумал, что, может быть, я, и, похоже, вы тоже, возможно, подхожу к этому совершенно иначе. Cheers
Anudeep Bulla
О, я не видел, что предлагает Google и Другой путь: p! Послушайте, я попытаюсь создать действие, которое выйдет из строя, если вы сначала вызовете onDestroy. Вы должны попробовать и это. Cheers
Sherif elKhatib
@AnudeepBulla вы можете проверить мои правки. И, кстати, можешь перестать пытаться. super.onвероятно, никогда не помешает вашей деятельности.
Sherif elKhatib
Вау. Спасибо за указатели. И этот, и @ User ответы предоставляют важный контекст. Если кто-либо из вас сможет обобщить ответы на этой странице, я отмечу его как принятый. Пожалуйста, укажите: 1. Ответы на этой странице. 2. Ответ @ Philip на этой странице 3. Ответ @ CommonsWare на этой странице 4. Это обсуждение Я бы хотел, но мне не нужны кредиты за ваши замечательные ответы. Cheers & Thanks
Anudeep Bulla
@AnudeepBulla Пожалуйста. Я не уверен, как мы собираемся решать, кто опубликует окончательную рецензию.
Vikram
2

Вы говорите, что Google предлагает метод 1, однако Дайан Хакборн, известный разработчик фреймворка Android, предлагает иначе см. Ссылку на форум Google .

Интуитивно понятен вызов суперкласса последним при уничтожении экземпляра в методах onPause, onStop и onDestroy и первым при создании экземпляра с помощью методов onCreate, onResume и onStart .

NickT
источник
Ссылка на пост Дайан Хакборн важна и подтверждает закономерность.
Ник Вестгейт,
1

С точки зрения Java, вот решение этой путаницы:

Почему this () и 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, конструктор объектов должен быть вызван каким-то образом, и он должен быть выполнен первым. Автоматическая вставка super () компилятором позволяет это. Принуждение к появлению super первым приводит к тому, что тела конструктора выполняются в правильном порядке: Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth

(1) Проверка того, что super является первым утверждением, недостаточна для предотвращения этой проблемы. Например, вы можете указать «super (someMethodInSuper ());» в вашем конструкторе. Это пытается получить доступ к методу в суперклассе до его создания, даже если super является первым оператором.

(2) Компилятор, похоже, реализует другую проверку, которая сама по себе достаточна для предотвращения этой проблемы. Сообщение: «Невозможно ссылаться на xxx до вызова конструктора супертипа». Следовательно, проверка того, что super является первым оператором, не требуется.

Просмотрите этот http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html

LOG_TAG
источник
Я прекрасно понимаю, что вы там выкладываете. Сначала вы вызываете конструкторы суперкласса, потому что они могут инициализировать ресурсы, которые могут понадобиться потомку; и деструкторы остаются последними, потому что вы, вероятно, не хотите стирать всех родителей в локальных ресурсах, делая их бессмысленными. Это именно то, что я хочу сказать. И поскольку onPause, onStop и onDestroy выполняют задачу сохранения информации о состоянии и более или менее предоставления ресурсов для GC (в некотором смысле уничтожая их), я вижу их аналогами деструкторам и, следовательно, считаю, что называть их последними имеет смысл. Нет?
Anudeep Bulla
Все, что вы сказали выше, - это именно то, что я имел в виду, когда сказал, что «сначала вызов супер методов имеет смысл на полупериоде создания». Я обеспокоен и сбит с толку в случае методов полуцикла разрушения, которые кажутся более похожими на деструкторы. Cheers
Anudeep Bulla
1

Самое важное, что нужно иметь в виду, - это super.onPause()неявные вызовы setResult(Activity.RESULT_CANCELED). Но setResultможет быть вызван только один раз, и все последующие вызовы игнорируются. Поэтому, если вы хотите передать какой-либо результат обратно в родительскую операцию, вы должны позвонить setResultсебе, прежде чем позвонить super.onPause(). Насколько я знаю, это самая большая ошибка.

Филип Шеард
источник
Вау, это кажется важным. Так что возникает ситуация, когда вызов супер-методов обязательно нужно отложить. Спасибо.
Anudeep Bulla
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Не могли бы вы сказать, откуда вы это взяли?
Викрам
Я был сбит с толку. На самом деле метод finish () вызывает setResult, а super.onBackPressed () вызывает finish (). Поэтому setResult обязательно нужно вызывать перед super.onBackPressed (). Я не уверен, существуют ли обстоятельства, при которых super.onPause () может вызвать вызов setResult, но я предпочитаю не рисковать.
Филип Шеард
1

ОБЕИ верны ИМО

Согласно документам

Производные классы должны вызывать реализацию этого метода суперклассом. В противном случае будет выброшено исключение.

Super всегда следует вызывать, если об этом прямо сказано в документации.

Однако вы можете выбрать, когда вызывать супер-метод.

Глядя на источник onPause

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

Следовательно, не имеет значения, до или после того, как он будет вызван. Тебе должно быть хорошо.

Но для лучшей практики вы должны сначала вызвать его.

Я рекомендую это в основном как механизм защиты: если есть исключение, superметод экземпляра уже будет вызван.

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

Сунил Мишра
источник
Прошу прощения, если вопрос был не совсем ясен в первый раз, но, пожалуйста, взгляните на него сейчас.
Anudeep Bulla
@AnudeepBulla Это то, что я вам объяснил. Вы можете использовать любой из них. Оба действительны.
Сунил Мишра
Насколько я понимаю, индивидуальная реализация методов onPause, onStop и onDestroy не является строго необходимой. Я сделал множество приложений без них. Итак, что вы имеете в виду, говоря, что супер методы должны всегда вызываться? Они вызываются неявно, даже без переопределения. Я также знаю, что оба работают. Я хочу знать, почему документы говорят, что сначала нужно вызвать super. И в случае, если вопрос все еще не очевиден, объясните, пожалуйста, ПОЧЕМУ, когда вы говорите: «Но для лучшей практики вы должны сначала позвонить»?
Anudeep Bulla
Если вы не переопределите, методы вызываются из, Base Classно если вы переопределите, необходимо, чтобы вы вызывали superelse, который у вас будетandroid.app.SuperNotCalledException
Сунил Мишра
1
Вы, кажется, неправильно поняли. Вопрос не в том, звонить или не звонить. Как вы указали, вы ДОЛЖНЫ это сделать, если вы их переопределите. Вопрос в том, когда?
Anudeep Bulla
0

Супер обратные вызовы необходимы для того, чтобы привести Activity в правильное состояние внутри системы.

Допустим, вы запускаете Activity, и система вызывает onCreate. Теперь вы можете переопределить его и, например, загрузить свой макет. Но ради системного потока вы должны вызвать super, чтобы система могла продолжить стандартную процедуру. Вот почему будет выброшено исключение, если вы его не вызовете.

Это происходит независимо от вашей реализации в onCreate. Это важно только для системы. Если бы не было ANR, у вас мог бы быть бесконечный цикл в любом обратном вызове, и Activity было бы поймано в этом. Таким образом, система знает, когда обратный вызов был завершен, и вызывает следующий.

Я знаю только одну ситуацию, когда нужен тайминг супервызова. Если вы хотите изменить стандартное поведение темы или дисплея и тому подобное в onCreate, вам нужно сделать это до того, как вы вызовете super, чтобы увидеть эффект. В противном случае, AFAIK, нет разницы, в какое время вы его вызываете.

Но чтобы позволить системе делать то, что она может, лучше всего поместить super в первую строку обратного вызова, за которым следует ваш код, если у вас нет веской причины прервать его.

Стив Бенетт
источник
Последовательность в onCreate кажется довольно понятной. Что происходит в методах уничтожения? Скажите onStop. Предположим, моя реализация onStop использует некоторые ресурсы, которые высвобождает супер-метод при вызове. Тогда имеет смысл вызвать супер-метод после моей реализации.
Anudeep Bulla
В идеале так и должно быть, верно. В нашей деятельности всегда будут ресурсы, которые есть у суперкласса, и некоторые другие. А те, которые не зависят от моей активности, могут в большинстве случаев зависеть от общих ресурсов суперкласса. Имеет смысл сначала иметь дело с моими ресурсами, а затем вызывать суперкласс для работы с общими. Почему тогда Google говорит, что мы «ДОЛЖНЫ» сначала вызывать методы суперкласса?
Anudeep Bulla
О каком ресурсе вы говорите, к которому вы можете получить доступ в onCreate, но не в onDestroy?
Стив Бенетт
У меня нет варианта использования. Мне просто интересно, как это зависит от стиля ООП. Конструкторы суперклассов вызываются первыми, перед вашей реализацией, а деструкторы суперклассов вызываются последними, после вашей реализации, верно? onPause, onStop и onDestroy не являются строго деструкторами, но они, как правило, делают одно и то же, верно? По крайней мере onDestroy и в основном onStop тоже .. нет?
Anudeep Bulla
Смотрите обратные вызовы в способе изменения состояния, а не как конструктор / деструктор. У каждого обратного вызова есть необходимость, например, создать (готово к использованию) / уничтожить (ваш последний шанс для взаимодействия) Activity или поместить его на передний план / в фоновый режим. Обратные вызовы существуют, чтобы вы могли контролировать свои ресурсы в потоке системы. Система просто проверяет, в каком состоянии она находится, и обрабатывает ее соответственно. Ресурсы, которые вы используете, и ресурсы, которыми управляет система, независимы друг от друга и не будут пересекаться.
Стив Бенетт,