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

时间:2011-08-11 12:14:31

标签: android android-service listener android-binder

我有一个LocalService,它使用一些API公开Binder。我创建了一个Service Listener,就像这样:

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

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

我认为这是Mark L. Murphy(Commonsware)在“繁忙的编码器Android开发指南”中描述的问题:

  

最大的问题是确保活动在完成后撤回听众。

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

谢谢!

5 个答案:

答案 0 :(得分:8)

我有同样的问题。我正在使用AIDL在远程服务中工作。当我尝试使用foreach循环中的ArrayList Collection中的remove方法取消注册我的侦听器时,我遇到了这个问题,因为我没有在比较中使用asBinder。在搜索论坛解决方案时,我会在Android API中找到RemoteCallbackList类。这个课程完全符合我的需要,我认为你应该做的事情,以简单的方式,为所有涉及这项任务的艰苦工作采取所有的责任。

来自Android API:

  

要使用此类,只需与您的服务一起创建一个实例,并将其注册(E)和取消注册(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();

答案 1 :(得分:4)

您展示的代码用于绑定服务。您没有显示使用该服务注册监听器的位置。您显然是基于您的问题和对onResult()方法的引用。鉴于你的问题的性质,我猜你正在做的是:

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

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

    配置更改,特别是在预片段世界中,使这变得复杂。这就是为什么this sample project(和the book中的附带材料)如此icky的原因。绑定很麻烦 - 如果您从旧活动中取消绑定,并且没有其他任何东西保持服务,则服务将在新活动有机会绑定之前关闭。绑定也是状态 - 你不能简单地解除绑定,以免泄漏东西。

    因此,食谱变为:

    1. 使用unbindService() onCreate()
    2. 绑定到Application中的服务
    3. Context中,在onServiceConnected()
    4. 上调用setListener()方法
    5. Binder中,请注意您正在进行配置更改,并返回包含onRetainNonConfigurationInstance()Object和所有内容的Binder Listener你所在州的其余部分
    6. onCreate()中,使用getLastNonConfigurationInstance() - 如果是null,则按正常方式继续,但如果不是null,请抓住BinderListener并且不重新绑定并重新注册监听器
    7. onDestroy()中,如果上面步骤3中的标记为false(即我们 正在进行配置更改),请调用removeListener() Binder上的方法,然后调用unbindService()
    8. 使用带有setRetainInstance(true)的片段可能会简化这一点,但我还没有完成样本。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

我终于解决了这个问题(不,我没有长时间处理它:D)。

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