在onPause,onStop和onDestroy方法中调用超类方法的正确顺序是什么? 为什么?

我刚刚通过Android开发人员网站,在Activity Life Cycle上进行了刷新,在每个代码示例中,超类方法旁边都有一个注释:“始终调用超类方法”。

虽然这在创build半周期中是有意义的:onCreate,onStart和onResume,我有点困惑,什么是在破坏半循环的正确的过程:onPause,onStop,onDestroy。

首先破坏特定于实例的资源,然后销毁实例特定资源可能依赖的超类资源才有意义,而不是相反。 我错过了什么?

编辑 :由于人们似乎对这个问题的意图感到困惑,我想知道的是以下哪一项是正确的? 为什么?

1.Googlebuild议

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

另一种方式

  @Override protected void onStop() { //my implementation here super.onStop(); } 

在销毁实例特定资源可能依赖的超类资源之前,首先销毁实例特定的资源是合理的,而不是相反。 但是意见却不是这样。 我错过了什么?

在我看来:不是一回事。

马克(也就是SO上的CommonsWare)的这个答案揭示了这个问题: 链接 – 对超类方法的调用应该是第一个语句吗? 。 但是,你可以在他的回答中看到下面的评论:

但为什么官方文档在onPause()中说:“总是调用超类的方法?

回到原点。 好的,我们从另一个angular度来看这个。 我们知道Java语言规范没有规定必须放置对super.overridenMethod()的调用的命令(或者如果必须放置该调用)。

在类Activity的情况下, super.overridenMethod()调用是必需和强制的

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

mCalledActivity.onStop()设置为true。

现在,唯一要讨论的细节是订购。

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()会干扰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(); } .... } 

而且,从android sdk中包含的LunarLander示例应用程序:

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

总结和值得一提的:

用户Philip Sheard :提供了一个场景,在使用startActivityForResult(Intent)启动Activity的情况下,必须延迟对super.onPause()的调用。 super.onPause() 之后使用setResult(...)设置结果将不起作用。 他后来在他的回答的评论中澄清了这一点。

User Sherif elKhatib :解释为什么让超类首先初始化资源,最后从逻辑中摧毁资源:

让我们考虑一个你下载的库,它有一个LocationActivity,它包含一个提供位置的getLocation()函数。 很可能, 这个活动需要在onCreate()中初始化它的东西,这会迫使你先调用super.onCreate 。 你已经这样做了,因为你觉得这是有道理的。 现在,在您的onDestroy中,您决定要保存SharedPreferences中的位置。 如果先调用super.onDestroy,则在一定程度上getLocation将在此调用之后返回null值,因为LocationActivity的实现会使onDestroy中的位置值无效。 这个想法是,如果发生这种情况,你不会责怪它。 因此,在完成自己的onDestroy之后,您可以在最后调用super.onDestroy。

他继续指出:如果一个孩子class级与父母class级的资源依赖性相super.X()super.X()调用不需要遵守任何订单规范。

在这个页面上看到他的回答,通过super.onDestroy()调用的位置确实影响程序逻辑的场景。

从Mark的回答

您重写的方法是组件创build(onCreate(),onStart(),onResume()等)的一部分,您应该链接到超类作为第一个语句 ,以确保Android有机会在您之前完成工作试图做一些依靠已经完成的工作的事情。

你重载的方法是组件销毁的一部分(onPause(),onStop(),onDestroy()等),你应该先做你的工作,并链接到超类作为最后一件事 。 这样,如果Android清理了一些你的工作所依赖的东西,那么你将首先完成你的工作。

返回非void的方法(onCreateOptionsMenu()等),有时你会链接到return语句中的超类,假设你没有专门做一些需要强制返回值的东西。

其他的一切 – 比如onActivityResult() – 总的来说取决于你。 我倾向于作为第一件事和超级类别联系在一起,但是除非遇到问题,否则后面的链接应该没问题。

Bob Kerns从这个主题 :

这是一个很好的模式[(Markbuild议的模式)],但是我发现了一些例外。 例如, 我想应用到我的PreferenceActivity的主题不会生效,除非我把它放在超类的onCreate()之前。

用户史蒂夫·贝内特也提请注意:

我只知道一个情况,超级电话的时间是必要的。 如果你想改变onCreate的主题或者显示的标准行为,你必须在你调用super之前看到效果 。 否则AFAIK在你打电话时没有区别。

用户Sunil Mishra证实,在调用Activity类的方法时,顺序(很有可能)不起作用。 他还声称, 首先调用超类方法被认为是最佳实践 。 但是,我不能证实这一点。

用户LOG_TAG :解释为什么对超类构造函数的调用需要成为之前的一切。 在我看来,这个解释并没有增加被问到的问题。

结束注释 :信任, validation。 本页上的大部分答案都遵循这种方法来查看Always call the superclass method first的语句是否具有逻辑支持。 事实certificate,事实并非如此。 至less,不是在class级活动的情况下。 通常,应该通读超类的源代码来确定是否需要对super方法进行sorting调用。

既然(你说)先调用super onCreate是有道理的:考虑一下。

当我想创build,我的超级创build资源>我创build我的资源。

相反:(有点堆栈)

当我想摧毁,我摧毁我的资源>我的超级摧毁他的资源。


从这个意义上讲,它适用于任何一对函数(onCreate / onDestroy,onResume / onPause,onStart / onStop)。 自然,onCreate将创build资源,onDestroy将释放这些资源。 顺便说一句,同样的证据适用于其他夫妇。

让我们考虑一个你下载的库,它有一个LocationActivity,它包含一个提供位置的getLocation()函数。 很可能,这个活动需要在onCreate()中初始化它的东西,这会迫使你先调用super.onCreate。 你已经这样做了,因为你觉得这是有道理的。 现在,在您的onDestroy中,您决定要保存SharedPreferences中的位置。 如果您先调用super.onDestroy,那么getLocation将在一定程度上在此调用之后返回null值,因为LocationActivity的实现将取消onDestroy中的位置值。 这个想法是,如果发生这种情况,你不会责怪它。 因此,在完成自己的onDestroy之后,您可以在最后调用super.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,并且稍后,我想创build延伸您的活动的SherifElKhatibActivity ? 我应该以什么顺序调用super.do函数? 这是最终一样的事情。


至于你的问题:

我认为Google的意图是告诉我们:无论在哪里,请致电超级。 作为一个惯例,当然可以在开始的时候调用它。 谷歌当然有最聪明的工程师和开发人员,所以他们可能做了一个很好的工作隔离他们的超级电话,而不是干扰子女的电话。

我尝试了一下,可能并不容易(因为我们试图certificate是错误的Google),因此创build一个简单的活动,因为何时超级被调用。

为什么?

这些函数中所做的任何事情对于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来得到不同的结果。 例如:

创build一个应用程序类来计算当前正在运行的活动的数量:

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

以下可能没有意义,或者不是一个好的做法,但它只是为了certificate一个观点(人们可能会发现一个更真实的情况)。 创buildMainActivity,当它完成时,它应该是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)); } } 

如果您在onDestroy的开头调用super.onDestroy,则GoodBye活动将启动。 如果您在onDestroy的末尾调用super.onDestroy,GoodBye活动将不会启动。

当然,这也不是最好的例子。 但是这表明Google在这里搞砸了一点。 其他任何variables都不会影响您的应用的行为。 然而,将这些派发添加到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; } 

注意他们在这个函数的某个地方调用了Activity的onStop。 因此,他们可能会在调用onStop之前或之后放置所有代码(包含在super.onStop中),然后仅使用空的onStop超级函数通知子类有关onStop,甚至不添加SuperNotCalledException或检查这个调用。

为此,如果他们将这个调度调用到performDestroy中的ActivityLifeCycle中,而不是在super.onDestroy的末尾调用它,那么无论我们何时调用super,我们的活动的行为都是一样的。

无论如何,这是他们做的第一件事(有点不对),它只在API 14中。

最要紧的是super.onPause()隐式调用setResult(Activity.RESULT_CANCELED) 。 但是setResult只能被调用一次,所有的后续调用都会被忽略。 所以如果你想把任何一种结果推回到父活动,你必须先调用setResult然后调用super.onPause() 。 就我所知,这是最大的问题。

两者都是正确的国际海事组织

根据文件

派生类必须调用超类的这个方法的实现。 如果他们不这样做,就会抛出exception。

Super方法应该总是在文档明确说明的时候调用。

但是,您可以select何时调用超级方法。

onPause的来源

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

因此,无论是之前还是之后, 你应该很好。

但是为了最好的实践,你应该首先调用它。

我推荐它主要作为一种保护机制:如果有一个exception,那么super实例方法已经被调用。

将这些呼叫放在第一行也可以帮助您避免将来发生错误,例如删除方法中的代码,以及意外地删除对超类的调用。

你说谷歌build议方法1,但是一个着名的Android框架工程师Dianne Hackbornbuild议另外看看谷歌论坛链接 。

当在onPause,onStoponDestroy方法中销毁一个实例时, 最后调用超级类是最直接而使用onCreate,onResumeonStart方法创build实例时首先要 调用它

为了使系统内部的活动处于正确的状态,需要使用callback的超级方法。

比方说,你开始你的活动,并由系统调用onCreate。 现在你可以覆盖它,例如加载你的布局。 但是为了系统stream程,你必须调用super,系统可以继续使用标准的程序。 这就是为什么如果你不打电话就会抛出一个exception。

这是独立于你在onCreate上的实现。 这只是系统的重要组成部分。 如果没有ANR,你可以在任何callback中有一个无限循环,活动将被捕获。 所以,系统知道什么时候callback已经结束,而不是调用下一个。

我只知道一个情况,超级电话的时间是必要的。 如果你想改变onCreate的主题或者显示的标准行为,你必须在你调用super之前看到效果。 否则AFAIK在你打电话时没有区别。

但是让系统尽可能地把超级放在callback的第一行,然后是你的代码,如果你没有足够的理由来解决它的话。

从java的angular度来看这里是一些解决这个混淆的方法:

为什么this()和super()必须是构造函数中的第一个语句?

父类的构造函数需要在子类的构造函数之前调用。 这将确保如果您在构造函数中调用父类的任何方法,父类已经正确设置。

你正在做什么,将parameter passing给超级构造函数是完全合法的,你只需要像你在做的那样内联地构造这些参数,或者把它们传递给你的构造函数,然后传递给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中的每个类都是从Objectinheritance的,因此必须以某种方式调用Object构造函数,并且必须先执行它。 编译器自动插入super()允许这样做。 强制超级先出现,强制构造函数体执行的顺序是:Object – > Parent – > Child – > ChildOfChild – > SoOnSoForth

(1)检查超级是第一个陈述是不足以防止这个问题。 例如,你可以把“super(someMethodInSuper());” 在你的构造函数。 尽pipesuper是第一个语句,但它试图在构造超类之前访问一个方法。

(2)编译器似乎实现了一个不同的检查,这本身足以防止这个问题。 该消息是“在超types构造函数被调用之前不能引用xxx”。 因此,检查超级是第一个陈述是没有必要的

请浏览http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html