Каков правильный порядок вызова методов суперкласса в методах onPause, onStop и onDestroy? и почему?
Я просто просматривал сайт разработчика Android, обновляя жизненный цикл активности, и в каждом примере кода есть комментарий рядом с методами суперкласса, который говорит: "Всегда сначала вызывайте метод суперкласса".
хотя это имеет смысл в полупериоде создания: onCreate, onStart и onResume, я немного запутался в том,что такое правильная процедура по разрушению полупериода : onPause,onStop, onDestroy.
уничтожение экземпляра конкретные ресурсы во-первых, прежде чем уничтожать ресурсы суперкласса, от которых могут зависеть конкретные ресурсы экземпляра, имеет смысл, а не наоборот.Но комментарии говорят об обратном. Чего мне не хватает?
Edit: поскольку люди, похоже, путаются в отношении намерения в вопросе, я хочу знать, что из следующего правильно? А ПОЧЕМУ ?
1.Гуглить предлагает
@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();
}
7 ответов:
сначала уничтожить ресурсы, относящиеся к экземпляру, перед уничтожением ресурсы суперкласса, которые могут зависеть от конкретных ресурсов экземпляра на смысл, а не наоборот. Но комментарии предполагают иначе. что я упустил?
по-моему: ни одной вещи.
этот ответ от Марка (он же CommonsWare на SO) проливает свет на этот вопрос:Link - должен ли вызов метода суперкласса быть первое утверждение?. Но тогда вы можете увидеть следующий комментарий, оставленный на его ответ:
но почему официальный doc говорит:" всегда вызывайте метод суперкласса первым " в onPause()?
назад к квадрату один. Ладно, давайте посмотрим на это с другой стороны. Мы знаем, что спецификация языка Java не укажите порядок, в котором вызов
super.overridenMethod()
должен быть размещен (или если вызов должен быть размещен вообще).In случай классной деятельности,
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
конечно. Посмотрите на тело метода для активности.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()
, вы будете в порядке. Деятельность.onStop () имеет аналогичное тело метода. Но взгляните на Деятельность.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(); } .... }
резюме и достойные упоминания:
Пользователь Philip Sheard : представлен сценарий, в котором вызов
super.onPause()
должно быть отложено в случае начала работы с помощьюstartActivityForResult(Intent)
. Установка результата с помощьюsetResult(...)
послеsuper.onPause()
не будет работать. Позже он уточняет это в комментариях к своему ответу.пользователь Sherif elKhatib : объясняет, почему позволяешь суперкласс инициализирует свои ресурсы первым и уничтожает свои ресурсы последним следует из логики:
давайте рассмотрим библиотеку, которую вы загрузили, которая имеет LocationActivity это содержит функцию getLocation (), которая предоставляет расположение. Скорее всего, эта деятельность должна будет инициализировать свой материал в onCreate () который заставит вас позвонить супер.onCreate first. Вы уже сделайте это, потому что вы чувствуете, что это имеет смысл. Теперь, в вашем onDestroy, вы решаете, что хотите сохранить местоположение где-то в SharedPreferences. Если вы позвоните супер.onDestroy во-первых, это к a в определенной степени возможно, что getLocation вернет нулевое значение после этого вызова, потому что реализация LocationActivity обнуляет значение местоположения в onDestroy. Идея в том, что вы не буду винить его, если это произойдет. поэтому, вы бы позвонили супер.onDestroy в конце после того как вы закончите с вашим собственным onDestroy.
он продолжает указывать: если дочерний класс надлежащим образом изолирован (с точки зрения зависимости от ресурсов) от родительского класса, то
super.X()
звонки не должны придерживаться какой-либо спецификации заказа.посмотреть свой ответ на этой странице, чтобы прочитать сценарий, где размещение
super.onDestroy()
вызов тут влияет на логику программы.из ответа Марка:
методы, которые вы переопределяете, которые являются частью создания компонента (onCreate(), onStart (), onResume () и др.), вы должны приковаться к суперклассу как первое утверждение, чтобы убедиться, что Android имеет свой шанс сделать ее работайте, прежде чем пытаться сделать что-то, что зависит от этой работы это было сделано.
методы, которые вы переопределяете, которые являются частью компонента разрушение (onPause (), onStop (), onDestroy () и др.), вы должны сделать ваша работа в первую очередь и цепочка к суперклассу как последнее. Что кстати, в случае, если Android очищает то, от чего зависит ваша работа, сначала ты сделаешь свою работу.
методы, которые возвращают что-то кроме void (onCreateOptionsMenu () и др.), иногда вы цепляетесь к суперкласс в инструкции return, предполагая, что вы не являетесь в частности, делать что-то, что должно заставить конкретный возврат значение.
все остальное -- например onActivityResult () -- это зависит от вас, в целом. Я, как правило, цепочка к суперклассу, как первое, что, но если вы не сталкиваетесь с проблемами, цепочка позже должна быть штраф.
Боб Кернс С этой теме:
это хороший шаблон [(шаблон, который предлагает Марк выше)], но я нашел некоторые исключения. Например, тема, которую я хотел применить к моей PreferenceActivity не будет принимать эффект, если я не поставлю его перед суперклассом onCreate ().
Пользователь Steve Benett также обращает на это внимание:
я знаю только одну ситуацию, где время Super вызова необходимый. если вы хотите изменить стандартное поведение тема или дисплей и такие в onCreate, вы должны сделать это перед вызовом супер, чтобы увидеть эффект. В противном случае, насколько мне известно, нет никакой разницы который пора тебе позвонить.
Пользователь Сунил Мишра подтверждает, что порядок (скорее всего) не играет роли при вызове методов класса Activity. Он также утверждает, что вызов методов суперкласса сначала считается лучшей практикой. Однако я не мог это подтвердить.
User LOG_TAG : объясняет, почему вызов суперкласса конструктор должен быть перед всем остальным. На мой взгляд, это объяснение не вопрос.
конец Примечания: доверие, но проверка. Большинство ответов на этой странице следовать этому подходу, чтобы увидеть, если заявление
Always call the superclass method first
имеет логической основы. Как оказалось, это не так; по крайней мере, не в случае классовой деятельности . Как правило, следует прочитать исходный код суперкласса, чтобы определить, является ли требование упорядочивания вызовов методов super.
поскольку (вы говорите) имеет смысл сначала вызвать super onCreate: подумайте об этом.
когда я хочу создать, мой супер создает свои ресурсы > я создаю свои ресурсы.
наоборот: (вроде стека)
когда я хочу уничтожить, я уничтожаю свои ресурсы > мой супер уничтожает свои ресурсы.
в этом смысле он применяется к любой паре функций (onCreate/onDestroy, onResume/onPause, onStart/onStop). Естественно, onCreate будет создавать ресурсы и onDestroy освободит эти ресурсы. Кстати, то же самое доказательство применимо и к другим парам.
давайте рассмотрим библиотеку, которую вы загрузили, которая имеет LocationActivity, которая содержит функцию getLocation (), которая предоставляет местоположение. Скорее всего, эта активность должна будет инициализировать свой материал в onCreate (), который заставит вас вызвать super.onCreate сначала. Вы уже делаете это, потому что вы чувствуете, что это делает чувство. Теперь, в вашем onDestroy, вы решите, что хотите сохранить местоположение где-то в SharedPreferences. Если вы позвоните супер.onDestroy во-первых, в определенной степени возможно, что getLocation вернет значение null после этого вызова, поскольку реализация LocationActivity обнуляет значение location в onDestroy. Идея в том, что вы не будете винить его, если это произойдет. Поэтому вы бы назвали Супер.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, будет иметь другой результат, основанный на том, когда вы вызываете 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 activity, когда он закончен и когда это последнее действие:
@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)); } }
если вы называете супер.onDestroy в начале вашего onDestroy, the Прощай деятельность будет запущена. Если вы позвоните супер.onDestroy в конце вашего onDestroy, прощание деятельность не будет запущена.
конечно, это не оптимальный пример. Однако это показывает, что Google облажались немного. Любая из других переменных не повлияла бы на поведение вашего приложения. Однако добавление этих отправлений в onDestroy заставило супер каким-то образом вмешаться в ваш подкласс.
Я говорю, что они испортили по другой причине, как что ж. Мало того, что они (до 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 где-то в этой функции. Поэтому они могли бы также поместить весь код (включенный в супер.onStop) до или после вызова onStop, а затем просто уведомляет подклассы о onStop, используя пустые суперфункции onStop и даже не добавляя исключение SuperNotCalledException или проверку этого вызова.
для этого, если они вызвали эту отправку в ActivityLifeCycle в performDestroy вместо вызова его в конце super.onDestroy, поведение нашей деятельности было бы таким же, независимо от того, когда мы позвонили супер.
в любом случае это первое, что они делают (немного ошибся) и это только в API 14.
самое главное, чтобы иметь в виду, что
super.onPause()
неявно называетsetResult(Activity.RESULT_CANCELED)
. НоsetResult
можно назвать только один раз, и все последующие вызовы игнорируются. Поэтому, если вы хотите вернуть какой-либо результат обратно в родительскую активность, вам нужно позвонитьsetResult
себя, до вы называетеsuper.onPause()
. Это самая большая проблема, насколько я знаю.
оба верны ИМО
согласно документам
производные классы должны вызывать реализацию суперкласса этого метода. Если они этого не сделают, будет выдано исключение.
Super
метод всегда должен вызываться, когда документация явно говорит об этом.однако вы можете выбрать, когда вызывать супер метод.
глядя на источник
onPause
protected void onPause() { getApplication().dispatchActivityPaused(this); mCalled = true; }
следовательно, независимо от того, до или после того, как он называется. Ты должен быть хорошим.
но для лучшей практики, вы должны называть его первым.
Я рекомендую его в основном как механизм защиты: если есть исключение, то
super
метод экземпляра уже были названы.кроме того, размещение этих вызовов на первой строке поможет вам избежать ошибок в будущем, таких как удаление кода в метод и случайное удаление вызова суперкласса.
вы говорите, что Google предлагает метод 1, однако Дайанн Хакборн, известный инженер Android framework, предлагает иначе посмотреть Ссылка На Форум Google.
имеет смысл интуитивно назвать супер класс последние, когда уничтожение экземпляр в onPause, onStop и onDestroy методы и первый, когда создания экземпляр с методами onCreate, onResume и onStart.
супер обратных вызовов необходимо поставить деятельность в правильном состоянии внутренне для системы.
допустим, вы начинаете свою деятельность и onCreate вызывается системой. Теперь вы можете переопределить его и загрузить свой макет. Но ради системного потока вы должны вызвать super, чтобы система могла продолжить стандартную процедуру. Вот почему исключение будет выдано, если вы не вызываете его.
Это происходит независимо от вашей реализации в onCreate. Это только importend для системы. Если бы не было ANR, вы могли бы иметь бесконечный цикл в любом обратном вызове, и активность была бы поймана в этом. Таким образом, система знает, когда обратный вызов был завершен, и чем вызывает следующий.
Я знаю только одну ситуацию, где время Super звонить надо. Если вы хотите изменить стандартное поведение темы или дисплея и т. д. в onCreate, вы должны сделать это перед вызовом super, чтобы увидеть эффект. В противном случае AFAIK нет никакой разницы, в какое время вы его называете.
но чтобы позволить системе делать то, что она может лучше всего поставить супер в первой строке обратного вызова, за которым следует ваш код, если у вас нет веских оснований для разрыва с ним.
С точки зрения java вот некоторое решение для этой путаницы:
почему это() и Super() должен быть первым оператором в конструкторе?
конструктор родительского класса должен быть вызван перед конструктором подкласса. Это гарантирует, что при вызове любых методов родительского класса в конструкторе родительский класс уже настроен правильно.
что вы пытаетесь сделать, передать args супер конструктор совершенно законен, вам просто нужно построить эти args inline, как вы делаете, или передать их в свой конструктор, а затем передать их в 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); } }
это показывает, что на самом деле, подполя должны быть inilialized перед суперклассом! Тем временем, требование java "защищает" нас от специализации класса, специализируя то, что аргумент super constructor
в тех случаях, когда родительский класс имеет конструктор по умолчанию, вызов super автоматически вставляется компилятором. Поскольку каждый класс в Java наследуется от объекта, конструктор объектов должен быть вызван каким-то образом, и он должен быть выполнен первым. Автоматическая вставка 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