【问题标题】:Activity as a listener and memory leaksActivity 作为监听器和内存泄漏
【发布时间】:2010-11-23 15:32:44
【问题描述】:

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

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

但是 :-) 我想知道 android 通常如何处理这种情况,例如,如果这是一个正在运行的服务。或者如果服务是本地服务,它使用 Bound 并将 Activity 作为侦听器传递给网络事件,同样的事情会发生,直到侦听器没有被移除,活动被泄漏并继续存在,但没有它,没有办法从网络获取回调... Intent 需要对可能很重的数据进行序列化和反序列化(例如位图?)

无论如何,假设我在收到的每个回复上都发送了一个意图,我如何获得 Activity 的意图(我知道 getIntent,但如果我得到另一个不相关的,我是否将其作为“事件' ?)

【问题讨论】:

    标签: android memory-leaks android-activity


    【解决方案1】:

    据我所知,Android 习惯于在 Activity 被销毁时将自己从侦听器列表中删除。这有点容易出错,但我认为这是公认的方法。

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

    【讨论】:

    • 我的想法完全正确.. 我认为这将是我的方法,我有点认为意图可以减轻任务。但我不确定它是缓解还是复杂化。
    【解决方案2】:

    Android 开发与其他平台(例如 BlackBerry)有很大不同。我无法为您提供快速的灵丹妙药解决方案,但以下是我对此的看法:

    我的一些适配器和我的一部分 活动是我的 DataListeners DataManagers,这意味着数据 manager 保留对它们的引用。

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

    还要记住Application sublass 实例并不总是存在于整个应用程序会话(从用户角度来看的会话)。如果您的应用程序进入后台,例如,由于来电,那么您的整个进程可能会被终止。详情见here。只要您Application sublass 包含一些状态,如果进程被杀死,您可能会错误地认为您的句柄指向一些非空实体。然而,在进入前台(和进程恢复)之后,这些可能只是空值,因为操作系统已经创建了一个 Application sublass 的新实例。

    【讨论】:

    • 你对这里的几个问题说得很对,但我很清楚我知道,我知道我的设计不是琐碎的或 100% 符合 android 设计准则,但这就是设计。我可以改变一些小事情,比如取消注册,或者使用意图作为时间,而不是重新注册普通听众。但我需要遵循我上面写的指导方针。关于杀死应用程序,你当然是对的,但机会很小,当应用程序恢复到它完成它的 onCreate 时,不会恢复其他活动,所以我能做的是检查我的请求是否在队列中或重新发送跨度>
    【解决方案3】:

    好的,让我更详细地描述问题和我找到的解决方案。 问题: 我有一个服务\网络线程需要通知通过它发送请求的活动请求或错误已以异步方式到达。使用侦听器模式需要我在发送请求之前或时设置侦听器,如下所示:

    mNetService.setRequest(request, this); 
    

    这是实现我的侦听器接口的 Activity。 但是这样做需要我从 onDestroy 中的服务中删除侦听器并返回侦听器,如果我曾经在 onCreate\onResume 中发回请求,但响应也可以在活动未在侦听时准确到达(横向\纵向事件),这要求我将 Error\Response 保留在服务中,直到 some1 将其拾取并重置它。

    我找到的解决方案: 使用广播和广播接收器。 这只是解决方案的一部分,但它让您可以监听广播(可以特定于特定的类类型,即 Activity)和动作。 由于我的所有活动都继承了一个基 Activity 类,因此我使它们都有一个 BroadcaseReciever 内部类,该类在其过滤器中侦听某些操作。 我是否在我的活动的 C'tor 中启用监听,监听器将在 onResume 中注册并在 onPause 中取消注册。 如果侦听器收到 onRecieved 事件,它将调用 Activity 中的一个方法(我可以在我的特定 Activity 中覆盖)并将我得到的 Intent 传递给它,该 Intent 可以包含来自响应的所有数据。

    唯一缺少的部分是如果 Activity 死了一秒钟然后广播才到达会发生什么?啊,这是个问题,所以 android 会引入一直存在的粘性广播,直到你用 removeStickyBroadcast(Intent) 将它们删除,所以当我的服务中的 ent 广播时,我发送粘性广播,当 Activity 获取我的广播时,它会删除它,所以它不会留下围绕并误导有关新响应的活动。 唯一的问题是,如果我发送请求,不要等待响应并立即转到下一个 Activity,在这种情况下,当我回到那个 Activity 时,它会认为它得到了响应。暂时还没有找到合适的解决方案。但它比我之前的解决方案要好。

    【讨论】:

      猜你喜欢
      • 2013-04-09
      • 2018-05-03
      • 2020-05-07
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      相关资源
      最近更新 更多