【问题标题】:Why is an Android Service not singleton when testing?为什么测试时 Android Service 不是单例的?
【发布时间】:2012-03-09 15:52:26
【问题描述】:

在运行大量测试套件时,我注意到我的一个 Android 服务不再是单例的。 Android 服务应该是单例的,但是当使用 ServiceTestCase 时,我的引用计数超过了 1。(在 onCreate 中增加,在 onDestroy 中减少)。 从测试用例调用 startService 或 bindService 应该会导致第二个 onBind 或 onStartCommand,但绝不应该在第一个 onDestroy 之前导致第二个 onCreate。

这是因为单元测试绕过了 Zygote 吗?如果是这样,我该如何解决这个问题?

【问题讨论】:

    标签: android service junit singleton


    【解决方案1】:

    我注意到我的一个 Android 服务不再是单例了

    无论您是在真实运行环境下还是在仪器测试下启动/绑定它,Android 服务都是单例的。单例是指堆中存在的唯一对象,它可以有多个引用指向它。

    从测试用例调用 startService 或 bindService 会导致第二个 onBind 或 onStartCommand

    这不是真的,正如官方开发指南中所述:“多个客户端可以同时连接到服务。但是,系统仅在第一个客户端时才调用服务的 onBind() 方法来检索 IBinder绑定。然后系统将相同的 IBinder 传递给任何其他绑定的客户端,而无需再次调用 onBind()。"

    但绝不应该在第一个 onDestroy 之前导致第二个 onCreate

    根据官方开发指南:“如果你确实允许启动和绑定你的服务,那么当服务已经启动时,系统不会在所有客户端解除绑定时销毁服务。相反,你必须通过调用 stopSelf() 或 stopService() 显式停止服务。"

    所以幕后的场景是,当你第一次调用启动或绑定服务时,会调用 Service.onCreate() 方法((在调用 onStartCommand() 或 onBind() 之前)在堆上创建一个唯一的对象并返回一个对它的引用(引用计数 = 1),之后,每次调用启动或绑定服务时,Service.onStartCommand() 都会在堆上不创建新对象(通过调用 Service.onCreate())的情况下执行,而是返回同一个对象的第二个引用点(现在引用计数 = 2),每次调用 unbind,引用计数减一,直到引用计数达到 0,调用 Service.onDestroy() 方法并最终清理堆上的对象。

    您可以在官方开发指南here 中找到我以斜体引用的所有详细信息。

    【讨论】:

    • onDestroy 仅在调用 stopSelf 和调用最后一次 unbind 时调用,但我不调用 stopself 因为此服务需要始终保持在运行状态。所以你说的是我必须自己在 onCreate() 中实现单例,因为它可以被多次调用?
    • 单例由框架处理。根据dev guide第一次创建服务时系统调用Service.onCreate(),如果服务已经在运行,则不调用该方法。Service.onStartCommand()每调用一次调用 startService() 的时间。我已经更新了我的答案。
    • 所以我的问题还是一样,因为我仍然看到 onCreate 被调用了两次!
    • @Huupke AFAIK onCreate() 在配置更改时可能会被多次调用。但不用担心 - Service 是单身 :)
    • " Service.onCreate() 方法被调用((在调用 onStartCommand() 或 onBind() 之前)在堆上创建唯一对象" -> onCreate 不是构造函数 - 实际上在哪里服务实例化(构造函数在哪里调用)?你知道吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    • 2010-11-21
    相关资源
    最近更新 更多