【问题标题】:Using Service as singleton in Android在 Android 中使用 Service 作为单例
【发布时间】:2016-01-26 21:26:58
【问题描述】:

创建一个作为单例工作的Service 是一种不好的做法吗?我的意思是 Service 永远不会停止,它包含一些其他引擎和 Activities 会使用的私有数据,所以 Service 可能有类似的东西:

public class CustomService extends Service {
    private List<Profile> mProfiles;
    private static CustomService instance;

     public static CustomService getInstance() {
         if(instance == null) {
             instance = new CustomService();
         }
         return instance;
     }

     public List<Profile> getProfiles() {
          return mProfiles;
     }

     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         ...
     }
     ...
}

使用Service 而不仅仅是一个单例的原因是它必须独立于应用程序工作,因为它在启动时连接一个永远不应该关闭且不依赖于应用程序的 websocket。你会建议我做什么?有没有更好的方法来重用Service 以便从其他引擎和Activities 获得一些数据(例如mProfiles 数组)?

我在某处读到 Service 作为单例工作,但我不知道如何从应用程序中的任何其他点访问私有变量。

【问题讨论】:

  • 据我所知,您不应该自己创建服务实例,而应该使用startService() 使用上下文。我不确定使用new CustomService(); 的后果是什么
  • 您好,谢谢您的回答。但是startService会启动服务并调用onStartCommand,但这不是我想要的。我想在应用程序的 onCreate 方法上启动服务一次,然后从应用程序的任何其他点获取服务的私有变量

标签: android design-patterns singleton android-service android-lifecycle


【解决方案1】:

创建一个作为单例工作的服务是一种不好的做法吗?

它是多余的,并且按照您的建议,从 Android Service 作为应用程序组件的角度来看,它是执行其功能的应用程序组件

  • Application 生命周期,而它又受
  • 系统事件。

应用程序组件的这种意图是通过

  • 它在AndroidManifest.xml 中的声明,
  • 触发它(启动/绑定/注册)和
  • Application 中创建(由系统)组件的一个实例并将其“附加”到ApplicationThread/ActivityThread

也就是说,应用程序组件与操作系统进程托管的Application 实例相关联,并且不能独立运行


关于你的方法,有两种情况

1. CustomService 的默认构造函数是私有的,按照模式。

通过调用getInstance(),会创建CustomService 的单个实例。该实例只是一个Java 对象(单例),与Android Service 应用程序组件没有任何共同之处。系统永远不会调用onStart()onStartCommand() 等方法。

尝试使用startService(Intent) 启动“服务”(在清单中声明)将失败并返回IllegalAccessException: access to constructor not allowed

2. CustomService 的默认构造函数是公开的(根据发布的代码)。

如果服务在AndroidManifest 中声明并且默认构造函数为空,startService() 不会失败,但是getInstance() 将创建另一个CustomService 实例,它不会被视为Android @ 987654350@应用组件。

这不是单例。


你会建议我做什么?有没有更好的方法来重用服务,以便从其他引擎和活动中获得一些数据(例如 mProfiles 数组)?

按照the documentation 使用Service 并选择您需要的通信类型:

  • 单向通信(Activity--&gt;Service) - 使用started Service 并处理每个Intent(附加您的数据,如mProfiles,以防Profile 类实现@ 987654324@) 在onStartCommand();
  • 双向通信 (Activity &lt;-&gt; Service) - 使用 bound Service 并通过 IBinder 进行通信。

最后,Android 中的Service 是一个单例。系统中每个服务只有一个实例。它按需启动并处理所有待处理的Intents / 绑定客户端。一旦完成或明确停止,它将被销毁。

【讨论】:

  • 非常感谢您的回答。但是,有没有办法从引擎中获取服务的私有变量?我读过只有活动或服务可以绑定到服务,所以,我如何从广播接收器或另一个单例或引擎获取 mProfiles 数组(例如)?非常感谢。
【解决方案2】:

将服务创建为单例是不好的做法。您可以启动您的服务粘性,您可以通过它的名称检索您的服务,并从活动内部使用以下代码检查它是否工作。

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

【讨论】:

    【解决方案3】:

    如果(我还没有找到支持这一点的文档,但假设是这种情况)Android 框架只实例化了一次服务,那么您可以在 Service.onCreate 中初始化 instance。唯一的缺点是您无法保证何时调用它。即,如果您在 Application.onCreate 中调用 startService,您很可能需要等待一段时间才能实际实例化您的服务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多