gpt4 book ai didi

android - 当 Activity 通过 "Don' 被终止时不会触发 ActivityLifecycleCallbacks t keep Activity ”

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:05:16 27 4
gpt4 key购买 nike

在我的 Android 应用程序中,我有两个 Activity :

  • DemoActivity用按钮启动 SearchActivityIntent
  • SearchActivity

  • 该按钮是一个自定义的 ViewGroup:
  • SearchButton

  • 尽快 SearchButton它为生命周期事件注册(对应的 SearchActivity ):
    public class SearchButton extends CardView implements 
    Application.ActivityLifecycleCallbacks {

    @Override
    protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    Context applicationContext = getContext().getApplicationContext();
    if (applicationContext instanceof Application) {
    ((Application) applicationContext)
    .registerActivityLifecycleCallbacks(this);
    }
    }

    // ...

    事件消耗如下:
    // ...

    @Override
    public void onActivityStarted(Activity activity) {
    if (activity instanceof SearchActivity) {
    SearchActivity searchActivity = (SearchActivity) activity;
    searchActivity.addSomeListener(someListener);
    }
    }

    @Override
    public void onActivityStopped(Activity activity) {
    if (activity instanceof SearchActivity) {
    SearchActivity searchActivity = (SearchActivity) activity;
    searchActivity.removeSomeListener(someListener);
    }
    }

    曾经 SearchActivity已启动我将应用程序置于后台并将其返回到前台。可以看到如下调用栈:
    1. SearchButton.onActivityStarted // triggered by DemoActivity
    2. DemoActivity.onStart
    3. SearchButton.onActivityStarted // triggered by SearchActivity
    4. SearchActivity.addSomeListener
    5. SearchActivity.onStart

    如您所见,添加了监听器。这工作正常。

    问题

    一旦我启用 Don't keep activities在开发人员选项中,当我再次获取应用程序前台时,调用堆栈如下所示:
    1. DemoActivity.onCreate
    2. SearchButton.init // Constructor
    3. DemoActivity.onStart
    4. SearchActivity.onStart
    5. SearchButton.onAttachedToWindow
    6. DemoApplication.registerActivityLifecycleCallbacks

    这里的听众是 未添加 .想要的 onActivityStarted SearchActivity.onStart触发的回调是 失踪 .

    最佳答案

    简答

    您看到的是 onStart仅当 Activity 在后台一段时间后被带到前台时才从 View 调用。目前不可能从您的 Activity View 中看到较早的 Activity 事件,因为 View 层次结构仍在创建中,并且 View 尚未附加到窗口。

    当一个 Activity 从头开始初始化时, View 层次结构直到 onResume 之后才完全附加。 .这意味着一旦你 View 的 onAttachedToWindow被称为,onStart已经被执行了。如果您退出问题中提到的 Activity ,您仍然应该看到 onPause 的事件。等等。

    通常,如果您通过按主页按钮将 Activity 置于后台,则 Activity 会停止但不会被销毁。如果有足够的系统资源来执行此操作,它将与其 View 层次结构一起保留在内存中。当 Activity 恢复到前台时,它会调用 onStart,而不是从头开始创建它。并从它停止的地方恢复,而不重新创建 View 层次结构。

    “不保留 Activity ”选项确保每个 Activity 在离开前台后立即销毁,确保您的 View onAttachedToWindow总是在 onResume 之后调用因为每次都需要重新创建 View 层次结构。

    你可以做什么

    在不共享更多代码的情况下,不清楚为什么需要在 View 中设置监听器。看来无论如何都需要监听 Activity 的生命周期方法。

    如果监听器仅与 Activity 的生命周期相关联,您可能能够将其从 View 中完全提取出来并放入 Activity 中。

    如果它同时与 View 和 Activity 的生命周期相关联,您可以尝试在 View 的构造函数中注册 Activity 生命周期回调,因为此时上下文已经可用。

    或者,您可以使用 Google Maps 当前拥有的解决方案,例如在 map View 中。它要求 Activity 将所有生命周期方法代理到 View 。如果您的 View 与 Activity 的生命周期紧密相连,这可能很有用。 You can see the documentation here.

    第四个选项是使用 fragment 而不是 View ,因为它有自己的生命周期方法集。就我个人而言,我对 Fragment 不太满意,因为它们的生命周期可能更加复杂。

    更长的答案

    为了解释为什么会发生这种情况,我们需要深入研究 Android 的源代码。我在此处解释的内容特定于此实现,并且可能因制造商的更改而在 SDK 版本之间甚至在 Android 设备之间有所不同。您不应依赖代码中的这些细节。我将使用 Android Studio 附带的 SDK 23 源代码和构建 MTC19T 的 Nexus 6P。

    最容易开始调查的地方是 onAttachedToWindow方法。什么时候真正被调用? Its documentation says它是在 View 的表面创建以进行绘图后调用的,但我们对此并不满意。

    为了找到答案,我们为 View 设置了一个断点,重新启动应用程序以便重新创建 Activity,并调查 Android Studio 中的前几帧:

    "main@4092" prio=5 runnable
    java.lang.Thread.State: RUNNABLE
    at com.lnikkila.callbacktest.TestView.onAttachedToWindow(TestView.java:18)
    at android.view.View.dispatchAttachedToWindow(View.java:14520)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2843)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1372)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1115)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6023)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
    at android.view.Choreographer.doCallbacks(Choreographer.java:670)
    at android.view.Choreographer.doFrame(Choreographer.java:606)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    ...

    我们可以看到第一帧来自 View 的内部逻辑,来自父 ViewGroup,来自称为 ViewRootImpl 的东西,然后来自 Choreographer 和 Handler 的一些回调。

    我们不确定是什么创建了这些回调,但最接近的回调实现名为 ViewRootImpl$TraversalRunnable,因此我们将检查一下:
        final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
    doTraversal();
    }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

    有定义,下面是此方法中提供给 Choreographer 的回调实例:
        void scheduleTraversals() {
    if (!mTraversalScheduled) {
    mTraversalScheduled = true;
    mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    mChoreographer.postCallback(
    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    if (!mUnbufferedInputDispatch) {
    scheduleConsumeBatchedInput();
    }
    notifyRendererOfFramePending();
    pokeDrawLockIfNeeded();
    }
    }

    Choreographer 是在 Android 上的每个 UI 线程上运行的东西。它用于将事件与显示器的帧速率同步。使用它的一个原因是为了避免通过比显示器显示的速度更快地绘制东西来避免浪费处理能力。

    由于 Choreographer 使用线程的消息队列,我们​​无法在前面的帧中看到这个调用,因为在 Looper 处理消息之前没有进行调用。我们可以给这个方法设置一个断点,看看这个调用是从哪里来的:
    "main@4091" prio=5 runnable
    java.lang.Thread.State: RUNNABLE
    at android.view.ViewRootImpl.scheduleTraversals(ViewRootImpl.java:1084)
    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:913)
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:526)
    - locked <0x100a> (a android.view.ViewRootImpl)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3169)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2481)
    at android.app.ActivityThread.-wrap11(ActivityThread.java:-1)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    ...

    如果我们查看 ActivityThread 的 handleLaunchActivity , 有拨打 handleResumeActivity 的电话.在此之前是拨打 performLaunchActivity ,在该方法中调用 Instrumentation#callActivityOnCreate , Activity#performStart等等。

    因此,我们有证据表明 View 直到 onResume 之后才被附加。 .

    关于android - 当 Activity 通过 "Don' 被终止时不会触发 ActivityLifecycleCallbacks t keep Activity ”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39896382/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com