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

问题描述:

我有一个LocalService,它公开了一些Binder与一些API。我创建了一个服务侦听器,就像这样:当Activity关闭并重新打开时避免服务回调

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

后,我打电话了BinderdataServiceListener自曝,我得到的dataServiceListeneronResult()方法的响应方法。到目前为止,没有一种问题,一切都在起作用。 当我关闭正在等待服务侦听器回调的活动并立即重新打开时,会发生某种问题。尽管我重新实例化dataServiceListeneronCreate(),我得到两个回调,而不是一个,旧的来自被销毁的Activity和后者(右)。这种方式将结果混合在用户界面上。 有没有办法告诉服务或服务监听器,当活动结束时,必须避免回调。或者甚至可能销毁ServiceListener对象。

我觉得这是马克·L.·墨菲(Commonsware)中所描述的“忙编码器的指南Android的发展”的问题:

最大的缺点是,以确保活动缩回听众时它完成了。

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

谢谢!

我终于解决了这个问题(也没有,我没有这么长时间的工作:D)。

在调用FragmentonDestroy之前,向听众回叫。所以布尔型“dontupdate”值从未设置为false。在主要活动中重写onBackPressed解决了问题,因为我为每个片段调用了一个destroy()方法,该方法负责将布尔值设置为false。

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

+0

我怎样才能做到这一点?我只需要在Activity关闭后立即销毁我的监听器('onBackPressed()') – frapontillo

+0

是的,你可以在那里完成你的活动并确保它完成,你也可以重写“onDestroy()”方法服务.. –

+0

我的确如此,但它看起来就像onDestroy方法在onResult之后被调用,所以没有任何变化! – frapontillo

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

您显示的代码是用于绑定到服务的。您不会显示您正在向该服务注册侦听器的位置。您显然是基于您的问题和您对onResult()方法的参考。鉴于你的问题的性质,我要猜你正在做的是:

  1. 绑定到服务onCreate()
  2. onServiceConnected(),你正在呼吁Binder
  3. 某种 setListener()方法

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

配置变化,特别是在一个前碎片世界,使这变得复杂。这就是为什么this sample project(以及the book中附带的材料)太过恶劣的原因。绑定是棘手的 - 如果您从旧活动中解除绑定,并且没有任何其他服务保持服务,则在新活动有机会绑定之前,服务将关闭。绑定也是国家 - 你不能简单地解除绑定,以免泄漏东西。

所以,配方变为:使用ApplicationContext

  • onServiceConnected(),调用排序在Binder
  • onRetainNonConfigurationInstance()setListener()方法

    1. 绑定到服务中onCreate(),记的事实上,您正在进行配置更改,并返回一些Object,其中包含您的Binder,您的Listener以及您所有州的所有其他人
    2. onCreate(),使用getLastNonConfigurationInstance() - 如果它是null,继续正常的,但如果它不是null,守住那BinderListener,不重新绑定并重新注册听众
    3. onDestroy() ,如果上述步骤#3的标记是false(即,我们是而不是正在进行配置更改),请拨打Binder上的removeListener()方法,然后拨打unbindService()

    使用与setRetainInstance(true)片段可能可以简化这一些,虽然我还没有通过一个样本。

  • +0

    我就是这么做的。 基本上,我有一个活动与多个片段。每个片段可以有一个或多个服务绑定,因为它可能需要同时执行多个任务。 在主要活动的'onBackPressed()'中,我通过'boolean'值将所有服务侦听器设置为某种非工作状态。然后我完成活动。但是这并不如预期的那样工作:如果我为'onBackPressed()'方法设置了断点,它肯定会起作用,但出于某种原因,没有断点,'onResult()'方法在'onBackPressed )'! – frapontillo

    +0

    @MacGyver:“我做到了。” - 好吧,你的描述似乎不匹配。例如,你会注意到我没有提到'onBackPressed()',部分原因是因为这个不足。 “每个片段可以有一个或多个服务绑定,因为它可能需要同时执行多个任务。” - 你不应该需要多个绑定。你只需要一个服务,因此一个'Binder'。 – CommonsWare

    +0

    好的,在所述片段的onDestroy()我现在有: 'dataServiceListener.serviceBinder.removeListener();' 'getActivity()getApplicationContext()unbindService(dataServiceListener.svcConn);' 然而,这并未。什么都不会改变。 'removeListener()'只是在'ServiceBinder'中执行'listener = null'。 – frapontillo

    我有同样的问题。我正在使用AIDL进行远程服务。当我尝试在foreach循环中使用ArrayList Collection中的remove方法取消注册我的监听器时,我遇到了这个问题,因为我没有在比较中使用asBinder。通过搜索解决方案,我找到了Android API中的RemoteCallbackList类。这个课程正是我所需要的,我认为你应该做的,在一个简单的方法,采取所有reponsabilites艰苦的工作,涉及这项任务。

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