当前位置: 首页 > 面试题库 >

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

王伯寅
2023-03-14
问题内容

我刚浏览了Android开发者网站,刷新了活动生命周期,在每个代码示例中,超类方法旁边都有一条注释,上面写着“始终先调用超类方法”。

尽管这在创建半周期(onCreate,onStart和onResume)中是有意义的,但对于销毁半周期的正确过程是什么,我还是有些困惑:onPause,onStop,onDestroy。

首先销毁实例专用资源,然后销毁实例专用资源可能依赖的超类资源,这是有道理的,而不是相反。我想念什么?

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

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();  
    }

问题答案:

首先销毁实例特定的资源,然后销毁实例特定资源可能依赖的超类资源是有道理的,而不是相反。但是这些评论暗示了另外的观点。 我想念什么?

我认为:没有一件事情。

Mark的这个答案(又名SO上的CommonsWare)阐明了这个问题:链接-
对超类方法的调用应该是第一个语句吗?
。但是,您可以在他的答案中看到以下评论:

但是,为什么官方文档在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();
    }
    ....    
}

并且,来自android sdk中包含的LunarLander示例应用程序:

public class LunarLander extends Activity {

    ....

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

总结和值得一提:

用户Philip Sheard
:提供一种方案,super.onPause()在这种情况下,如果Activity开始使用,则必须延迟呼叫startActivityForResult(Intent)。使用setResult(...)
after 设置结果super.onPause()将不起作用。后来,他在对答案的评论中对此进行了澄清。

用户Sherif elKhatib :从逻辑上解释为什么让超类首先初始化其资源并最后破坏其资源的原因:

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

他继续指出:如果子类与父类适当地隔离(就资源依赖而言),则super.X()调用不必遵循任何顺序规范。

在此页面上查看他的答案,以通读super.onDestroy()调用位置 确实 会影响程序逻辑的情况。

根据马克的回答

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

重写的方法是组件破坏的一部分(onPause(),onStop(),onDestroy()等),您应该首先完成工作并最后链接到超类
。这样,如果Android清理了您的工作所依赖的内容,则您将首先完成工作。

返回除void以外的内容的方法(onCreateOptionsMenu()等),有时您会链接到return语句中的超类,假设您没有专门执行需要强制特定返回值的操作。

总体而言,其他一切(如onActivityResult())都取决于您。首先,我倾向于链接到超类,但是除非遇到问题,否则稍后链接应该没问题。

Bob Kerns 从这个话题:

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

用户Steve Benett 也引起注意:

我只知道一种情况,需要超级调用的时间。 如果要更改主题或显示的标准行为,例如onCreate,则必须先调用super才能看到效果
。否则,AFAIK在您调用它的时间没有区别。

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

用户LOG_TAG :说明为什么对超类 构造函数 的调用必须先于其他所有。我认为,这种解释不会增加所要提出的问题。

结束语 :信任, 但请 验证。此页面上的大多数答案都采用这种方法来查看该语句Always call the superclass method first是否具有逻辑依据。事实证明,事实并非如此。至少,不是在Activity类的情况下。通常,应该通读超类的源代码,以确定是否需要对超类的方法进行排序调用。



 类似资料:
  • 问题内容: 对于具有所有带有公共静态方法的实用程序类,正确的方法是什么? 我应该使用最终班还是抽象班? 请提出建议。 例如: 要么 问题答案: 有自己的目的。如果您希望其他类()实现某些类功能,则可以使用abstract。 如果它只是实用程序类,但是您不希望其他类将其子类化,那么我将选择类。如果实用程序类只有方法,则您无法以任何方式覆盖它们,因此将它们也包含在类中也没有区别。

  • 这是我的密码 结果为上述结果之一。从调用仍然调用子类的,即使从词汇上讲,meth调用在超类内部!那么,当是私有的时候,为什么会有不同的行为呢? ___________edit____________ 代码是这样的吗 O/P将是 因此,即使超级类中的正在调用,但实际上子类的正在被调用。所以,方法调用不是词法意义上的!也就是说,即使看起来将调用超级类的meth,实际上它的子类的becoz子类实例首先调

  • 问题内容: 我正在与我的CompSci教授交谈,他建议将所有String 方法编写为: 而不是: 这两行都可以编译,但是我想知道第一种方法的好处是什么?我一直都是后一种方式。错了吗 什么是普通/常规? 问题答案: 第一种方法确保执行比较时不会收到 NullPointerException 。当您尝试在不存在的对象上调用方法时,抛出(发生)此异常。 以下是一些相关的切线:仔细阅读风险自负 不过要注意

  • 问题内容: 我已经用Google搜索过两次,但仍然不了解超类型方法。谁能解释一下这是什么吗? 问题答案: OOPS中有超类型和子类型的概念,在Java中,这种关系是通过继承实现的,即使用关键字: 在超类中声明的任何成员(字段,方法)都称为超类型。 因此在上面的上下文中,如果类具有类似 Set是class的超类型方法。 但是,请注意,如果还有另一个类,请说: 然后,方法 不是类的 超类型 ,因为类与

  • 问题内容: 这个问题应该比关于更多。 我有一个子类(在python 2.7中,numpy 1.6.2),并且我发现在对象时未列出的字段名称(因此,ipython的自动完成功能无效)。 为了修复它,我尝试在子类中重写,如下所示: 结果是:。(我发现这里实际上应该在python 3.3中工作…) 作为一种解决方法,我尝试了: 据我所知,这是可行的,但当然并不优雅。 问题: 后一种解决方案对我而言是否正