安卓系统:从最近使用应用按钮关闭应用时,OnDestroy方法没有被调用

32
当我们按下这个按钮时 ,我们会看到我们没有关闭的应用程序,就像这样:
但是,当我们想要从以下屏幕(下图)关闭一个应用程序时,方法onDestroy()不会被调用,然而该应用程序已经关闭。我需要在以这种方式关闭应用程序时调用onDestroy()。我该怎么做?

6
有很多情况下onDestroy()方法不会被调用,不要依赖于它。如果它被调用了,可以放心地使用它来进行一些清理工作,但是你的应用程序需要能够处理任何组件(Activity或Service)上onDestroy()方法未被调用的情况。请注意,避免改变原意。 - CommonsWare
@CommonsWare 所以我需要创建一个服务吗? - Curio
清除应用程序就相当于在桌面上终止进程。您的应用程序将在当前位置死亡。 - DeeV
3个回答

37
根据Android文档,退出应用程序时不能保证会调用onDestroy()方法。

"在某些情况下,系统将仅仅杀死活动的进程而不调用此方法"

https://developer.android.com/reference/android/app/Activity.html#onDestroy%28%29

相反,您可以创建一个服务,该服务将在运行您的活动的任务被销毁时收到通知。
创建服务类:
public class ClosingService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);

        // Handle application closing
        fireClosingNotification();

        // Destroy the service
        stopSelf();
    }
}

在清单文件中(在 application 标签内但是在任何 activity 标签之外)声明/注册您的服务:

<service android:name=".services.ClosingService"
             android:stopWithTask="false"/>

指定stopWithTask="false"将导致在进程中从任务中移除时触发您的服务中的onTaskRemoved()方法。
在调用stopSelf()销毁服务之前,您可以运行您的关闭应用程序逻辑。

当应用程序关闭且我们没有在应用程序中按下按钮时,我想发送通知。 - Curio
使用onDestroy()来接收应用程序关闭通知是行不通的,因为一个应用程序由服务、广播接收器、后台任务、活动等组成。例如,一个音乐播放应用程序即使其所有活动已被销毁也可能没有关闭,因为它可能还在运行音乐播放服务。 - Charlie
此外,在清单文件中还有以下服务代码行 android:enabled="true" android:exported="true" 它们是正确的吗? - Curio
导出意味着服务将可供其他应用程序使用,您希望将其保留/设置为false。将已启用设置为true,以使服务启用 :) - Charlie
3
似乎对我没反应,没有报错,只是不起作用。 - ChumiestBucket
显示剩余2条评论

1
你应该阅读有关活动生命周期的信息。关于onDestroy方法,它并不总是被调用。你不能依赖它。
请说明您想要实现什么,我将尝试提供更好的解决方案。
建议:
所以,如果我理解你的意思正确,我可以提出一个建议。启动一个服务,每N秒触发一个本地广播(对系统不会产生太大负担)。在活动中注册和BroadcastReceiver此广播。这样,您将获得true或false,具体取决于是否有任何BroadcastReceiver可以捕获您的LocalBroadcast。如果没有接收器,则检查某些SharedPreferences值,指示是否按下了Button。

除非是前台服务,否则一旦应用程序被销毁,后台运行的服务随时都可能被操作系统终止。那么,有什么更可靠的方法呢? - undefined
@AlphaGaming 在2017年,(安卓)世界还是相当不同的 :) - undefined

1
更有前途的方法是使用应用程序中的活动生命周期回调,而不是使用绑定服务。虽然接受答案中展示的方法可以工作,但服务将在后台运行,直到活动被终止,这是昂贵的。相反,我建议使用您实现的应用程序。
1)创建一个扩展Application的类,然后通过在Manifest文件中的Application标记的名称属性中提供其名称来使用它。
class MusicPlayerApplication: Application() {
    private val TAG = MusicPlayerApplication::class.java.simpleName

    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(object: ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity?) {

            }

            override fun onActivityResumed(activity: Activity?) {
            }

            override fun onActivityStarted(activity: Activity?) {
            }

            override fun onActivityDestroyed(activity: Activity?) {
                Log.d(TAG, "onActivityDestroyed: ")
                val activityName = activity!!.localClassName
            }

            override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
            }

            override fun onActivityStopped(activity: Activity?) {
            }

            override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
            }
        })
    }
}

AndroidManifest.xml

<application
            android:name=".MusicPlayerApplication"
....

我已经使用logcat测试了这种方法,我的onDestory没有被调用,但是回调中的onActivityDestroyed每次我从RAM中杀死活动时都会被调用,但是this doc说当一个活动的onDestory被调用时,onActivityDestroyed将被调用,但似乎并没有发生。然而,我认为这种方法比使用服务更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接