我有一个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开发指南”中描述的问题:
最大的问题是确保活动在完成后撤回听众。
我该怎么做?有没有办法在活动结束时摆脱无用的听众?
谢谢!
答案 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()
方法的引用。鉴于你的问题的性质,我猜你正在做的是:
onCreate()
onServiceConnected()
中,您在setListener()
Binder
方法
醇>
在这种情况下,如果我们忽略配置更改,解决问题的正确方法是在onDestroy()
中调用removeListener()
上的某个Binder
方法,然后调用{{ 1}}。
配置更改,特别是在预片段世界中,使这变得复杂。这就是为什么this sample project(和the book中的附带材料)如此icky的原因。绑定很麻烦 - 如果您从旧活动中取消绑定,并且没有其他任何东西保持服务,则服务将在新活动有机会绑定之前关闭。绑定也是状态 - 你不能简单地解除绑定,以免泄漏东西。
因此,食谱变为:
unbindService()
onCreate()
Application
中的服务
Context
中,在onServiceConnected()
setListener()
方法
Binder
中,请注意您正在进行配置更改,并返回包含onRetainNonConfigurationInstance()
,Object
和所有内容的Binder
Listener
你所在州的其余部分onCreate()
中,使用getLastNonConfigurationInstance()
- 如果是null
,则按正常方式继续,但如果不是null
,请抓住Binder
和Listener
并且不重新绑定并重新注册监听器onDestroy()
中,如果上面步骤3中的标记为false
(即我们 正在进行配置更改),请调用removeListener()
Binder
上的方法,然后调用unbindService()
。使用带有setRetainInstance(true)
的片段可能会简化这一点,但我还没有完成样本。
答案 2 :(得分:1)
我也有这个问题。您需要在完成后从服务中释放所有资源,侦听器和线程。
答案 3 :(得分:1)
您的活动必须注册/取消注册自己作为听众。您需要使用正确的生命周期回调方法,而不是onBackPressed()
。注册onStart()
,取消注册onStop()
。一种方法是使监听器成为服务的静态成员,并提供静态注册/取消注册方法。然后根据需要调用您活动中的那些。
答案 4 :(得分:0)
我终于解决了这个问题(不,我没有长时间处理它:D)。
在调用Fragment
onDestroy
之前进行了对侦听器的回调。所以布尔“dontupdate”值从未设置为false。在主活动中覆盖onBackPressed
解决了这个问题,因为我为每个片段调用了destroy()
方法,该方法负责将布尔值设置为false。