Activity 关闭并重新打开时避免服务回调

Posted

技术标签:

【中文标题】Activity 关闭并重新打开时避免服务回调【英文标题】:Avoid Service callback when Activity gets closed and re-opened 【发布时间】:2011-08-11 12:14:31 【问题描述】:

我有一个 LocalService,它使用一些 API 公开一个 Binder。我创建了一个服务监听器,就像这样:

if (dataServiceListener == null) 
    dataServiceListener = new DataServiceListener();
    mainActivity.getApplicationContext().bindService
        (new Intent(mainActivity, LocalService.class),
        dataServiceListener.svcConn, mainActivity.BIND_AUTO_CREATE);

在调用dataServiceListener 中的Binder 公开的方法后,我在dataServiceListener onResult() 方法中得到响应。到目前为止,没有任何问题,一切正常。 当我关闭等待服务侦听器回调的 Activity 并立即重新打开它时,会出现某种问题。尽管我在onCreate() 中重新实例化了dataServiceListener,但我得到了两个回调而不是一个,旧的来自被破坏的Activity,后者(右)一个;这样,结果就会在 UI 上混淆。 有没有办法告诉服务或服务侦听器,当活动完成时,必须避免回调。或者甚至可能销毁 ServiceListener 对象。

我认为这是 Mark L. Murphy(Commonsware)在“The Busy Coder's Guide to android Development”中描述的问题:

最大的收获是确保活动完成后收回侦听器。

我该怎么做?有没有办法在活动结束时摆脱无用的侦听器?

谢谢!

【问题讨论】:

【参考方案1】:

我有同样的问题。我在使用 AIDL 的远程服务中工作。当我尝试在 foreach 循环中使用 ArrayList 集合中的 remove 方法取消注册我的听众时遇到了这个问题,因为我没有在比较中使用 asBinder。在寻找解决方案时,我在 Android API 中找到了 RemoteCallbackList 类。这门课正是我需要的,我认为你应该做的,以一种简单的方式,为涉及这项任务的辛勤工作承担所有责任。

来自 Android API:

要使用此类,只需与您的服务一起创建一个实例,并在客户端注册和注销您的服务时调用其 register(E) 和 unregister(E) 方法。要回调已注册的客户端,请使用 beginBroadcast()、getBroadcastItem(int) 和 finishBroadcast()。

广播样本:

int i = callbacks.beginBroadcast();
while (i > 0) 
    i--;
    try 
        callbacks.getBroadcastItem(i).somethingHappened();
     catch (RemoteException e) 
    // The RemoteCallbackList will take care of removing
    // the dead object for us.
   

callbacks.finishBroadcast();

【讨论】:

【参考方案2】:

您展示的代码用于绑定到服务。您没有显示您在哪里注册该服务的侦听器。根据您的问题和您对onResult() 方法的引用,您显然是。鉴于您的问题的性质,我猜您正在做的是:

    绑定到onCreate()中的服务 在onServiceConnected() 中,您在Binder 上调用某种setListener() 方法

在这种情况下,如果我们忽略配置更改,解决问题的正确方法是在onDestroy() 中调用Binder 上的一些removeListener() 方法,然后调用unbindService()

配置更改,尤其是在片段前的世界中,使这变得复杂。这就是为什么this sample project(以及the book 中的随附材料)如此恶心的原因。绑定是棘手的——如果你从旧的活动中解除绑定,并且没有其他东西可以保留服务,那么服务将在新活动有机会绑定之前关闭。绑定也是状态——你不能简单地取消绑定,以免泄露东西。

所以,配方变成:

    使用ApplicationContext绑定到onCreate()中的服务 在onServiceConnected() 中,在Binder 上调用某种setListener() 方法 在onRetainNonConfigurationInstance() 中,记下您正在进行配置更改的事实,并返回一些Object,其中包含您的BinderListener 以及您的所有其他状态 在onCreate()中,使用getLastNonConfigurationInstance()——如果是null,照常进行,但如果不是null,请继续使用BinderListener,不要重复绑定并重新注册监听器 在 onDestroy() 中,如果上面第 3 步中的标志是 false(即,我们没有进行配置更改),请在 Binder 上调用一些 removeListener() 方法,然后拨打unbindService()

使用带有setRetainInstance(true) 的片段可能会简化一些,尽管我还没有完成示例。

【讨论】:

我就是这么做的。基本上,我有一个包含多个片段的活动。每个片段可以有一个或多个服务绑定,因为它可能需要同时执行多个任务。在主要活动的onBackPressed() 中,我通过boolean 值将所有服务侦听器设置为某种非工作状态。然后我完成活动。但这并没有按预期工作:如果我为 onBackPressed() 方法设置断点,它肯定有效,但由于某种原因,没有断点,onResult() 方法在 onBackPressed() 之前调用! @MacGyver:“我就是这么做的。” ——嗯,你的描述似乎不匹配。例如,您会注意到我没有提到onBackPressed(),部分原因是这还不够。 “每个片段可以有一个或多个服务绑定,因为它可能需要同时执行多个任务。” - 你不应该需要多个绑定。您只需要一项服务,因此需要一项Binder 好的,在片段的 onDestroy() 中,我现在有了:dataServiceListener.serviceBinder.removeListener(); getActivity().getApplicationContext().unbindService(dataServiceListener.svcConn); 但是,这并没有改变任何东西。 removeListener() 刚刚在ServiceBinder 中执行了listener = null 我不知道如何进一步帮助您。如果您的问题仍然是“我得到了两个回调而不是一个”,那么您需要弄清楚尽管您将其设置为 null,但谁仍在持有侦听器,并修复它,或者其他什么。 好的,那么您是说将侦听器设置为null 应该可以完成工作吗?我想我将编写一些基本上什么都不做的简单服务,然后尝试使用它。但你为什么在书中提到弱引用?【参考方案3】:

我也有这个问题。完成后,您需要从服务中释放所有资源、侦听器和线程。

【讨论】:

我怎样才能做到这一点?我只需要在 Activity 关闭后立即销毁我的听众 (onBackPressed()) 是的,您可以在活动完成的地方执行此操作并确保已完成,您还可以在服务中覆盖“onDestroy()”方法.. 我正是这样做的,但看起来onDestroy 方法在 onResult 之后立即被调用,所以没有任何变化!【参考方案4】:

您的活动必须将自己注册/取消注册为侦听器。您需要使用正确的生命周期回调方法,而不是 onBackPressed()。注册onStart(),注销onStop()。一种方法是让监听器成为服务的静态成员,并提供静态注册/注销方法。然后根据需要从您的活动中调用它们。

【讨论】:

【参考方案5】:

我终于解决了这个问题(不,我已经很久没有解决这个问题了:D)。

在调用FragmentonDestroy 之前对侦听器进行了回调。所以布尔“dontupdate”值从未设置为false。在主活动中覆盖 onBackPressed 解决了这个问题,因为我为每个片段调用了一个 destroy() 方法,负责将布尔值设置为 false。

【讨论】:

以上是关于Activity 关闭并重新打开时避免服务回调的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个倒数计时器,当屏幕关闭时停止并“等待”,重新打开时恢复。安卓

有没有办法在关闭并再次打开时不重新创建表单的实例?

RTI DDS 两个应用程序在同一域上发布数据。当一个应用程序关闭并重新打开时,它会丢失数据。怎么解决?

位置服务关闭和打开时地理定位不起作用

Android如何在屏幕关闭/打开时防止webview重新加载?

bootstrap-select 从关闭状态重新打开时的空选项