作为监听器的活动和内存泄漏

时间:2010-11-23 15:32:44

标签: android memory-leaks android-activity

我的应用程序有以下框架: 1.在后台(队列)中运行的网络线程,用于发出请求并获取异步响应。该线程在Application Object中启动和停止,因此它将从整个应用程序中退出。 2. DataManager,它也是Application的成员,并且具有从网络检索的数据类型的不同DataManagers。数据管理器本身是来自网络响应的监听器,因此在应用程序自身死亡之前它是安全的。 这是有问题的部分。我的一些适配器和部分活动是DataManagers的DataListener,这意味着数据管理器会保留对它们的引用。

当发生电话或其他电话事件时,我注意到该活动通常处于暂停状态且未被销毁,因此收到我的活动,这是可以的。当landscape \ portrait更改时,问题就开始了。因为我在Application绑定对象中保留了对活动的引用,所以一方面不能销毁活动,但事件仍然是监听器,只有错误的... 基本上我可以通过删除onDestroy中的监听器并保留配置布尔来告诉我请求已经完成问题来修复该问题,我只需要放置一个监听器并尝试从数据管理器中检索数据。

然而:-)我想知道android如何处理这种情况,例如,如果这是一个运行的服务。或者如果服务是一个本地服务使用了绑定并将活动作为网络事件的监听器传递,同样的事情发生,直到没有删除监听器,活动被泄露并继续存在,但没有它,没有办法从网络获得回调...... 一个Intent需要对可能很重的数据进行连续化和去链接(例如Bitmaps?)

然而,假设我发送了一个意图,我得到了每个respose,我如何得到活动的意图(我知道getIntent,但如果我得到另一个,不相关,我是否把它作为'事件'?)

3 个答案:

答案 0 :(得分:1)

从我收集的内容来看,Android上的习惯是在活动被销毁时将自己从侦听器列表中删除。这有点容易出错,但我认为这是普遍接受的做法。

您可以想象您的服务只接受一个侦听器,这可能适合您的情况,也可能不适合您的情况,并且当活动重新启动时,其注册DataManager将覆盖旧的活动,而旧活动又将被垃圾收集。缺点是,如果活动内存被破坏但服务仍然存在,则不会释放活动内存,因此最好从侦听器中删除活动。

答案 1 :(得分:1)

Android开发与其他平台(例如BlackBerry)有很大不同。我无法给你一个快速的银弹解决方案,不过这是我对此的想法:

  

我的一些适配器和我的一部分   活动是我的DataListeners   DataManagers,表示数据   经理保留对他们的引用。

操作系统根据lifecycle杀死活动。因此,您应该避免在Activity被OS销毁后应该存在的另一个对象中保留Activity的句柄。否则你会得到内存泄漏。

另请注意,Application子类实例并不总是适用于整个应用程序会话(从用户角度来看会话)。如果您的应用程序在后台进行,例如,由于来电,则您的整个过程都可能被终止。详见here。一旦Application子类包含某个状态,如果进程被终止,则该状态不会持久存在,您可能会错误地指望您的句柄指向某些非空实体。但是在进入前台(和进程还原)之后,这些可能只是空值,因为OS已经创建了Application子类的新实例。

答案 2 :(得分:0)

好的,让我来详细描述问题和解决方案。 问题: 我有一个服务\网络线程,需要通过它通知发出请求的活动,要求或错误已经以异步方式到达。使用Listener Pattern需要我在发送请求之前或之后设置监听器:

mNetService.setRequest(request, this); 

这是实现我的侦听器接口的Activity。 但是这样做需要我从onDestroy中的服务中删除监听器并返回监听器,如果我曾经在onCreate \ onResume上发回请求,但响应也可以在活动没有收听时准确到达(landscape \ portrait事件)要求我在服务中保留Error \ Response,直到some1选择它并重置它。

我找到的解决方案: 使用Broadcasts和BroadcastReciever。 这只是解决方案的一部分,但它让你有一个广播的监听器(可以特定于某个类类型意味着Activity)和动作。 由于我的所有活动都继承了一个基本的Activity类,我已经让它们都有一个BroadcaseReciever内部类,它可以监听它的过滤器中的某些动作。 如果我在我的Activity的C'tor中启用了监听,那么监听器将在onResume中注册并在onPause中取消注册。 如果监听器获得onRecieved事件,它将调用Activity中的一个方法(我可以在我的特定活动中覆盖)并传递给我的Intent,它可以包含响应中的所有数据。

唯一缺失的部分是如果活动死了一秒钟然后广播到达会发生什么?嗯,这是一个问题,所以android引用Sticky Broadcasts留在那里,直到你用removeStickyBroadcast(Intent)删除它们,所以当我从我的服务广播时发送Sticky广播,当Activity获取我的广播它删除它所以它不会留下围绕并误导了有关新抵达的活动。 唯一的问题是,如果我发送请求,不要等待响应并立即转到下一个活动,在这种情况下,当我回到该活动时,它会认为它得到了响应。尚未找到适当的解决方案。但它比我之前的解决方案更好。