如何使用构造函数实例化Android服务?

16

我有一个具有以下构造函数的服务:

public ShimmerService(Context context, Handler handler) {
    mHandler = handler;
}

我想实例化这个服务类。以下是我的代码,但我不确定在哪里传递参数:

private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder binder) {
        mShimmerService = ((ShimmerService.ShimmerConfigureBinder) binder)
                .getService();
        Toast.makeText(ConfigureShimmer.this,
                "Shimmer service has succesfully started.",
                Toast.LENGTH_SHORT).show();
    }

    public void onServiceDisconnected(ComponentName className) {
        mShimmerService = null;
    }
};

除了绑定、启动等其他设置都已完成。但是我在上面的代码中遇到了错误:

04-03 19:06:10.285: E/AndroidRuntime(16837): java.lang.RuntimeException: Unable to instantiate service com.milanix.androidecg.services.ShimmerService: java.lang.InstantiationException: can't instantiate class com.milanix.androidecg.services.ShimmerService; no empty constructor

我该如何解决这个问题?我需要传递参数到哪里?以下的代码可以工作,但它将服务类(service class)视为类而不是服务(service):
mShimmerService = new ShimmerService(this, mHandler);
7个回答

19

你不应该直接显式地构建服务(或活动、广播接收器)。Android系统会在内部进行这些构建。构建服务的正确方法是通过带有意图的startService();可以随意向该意图添加其他参数。

编辑:或者使用bindService()。然后,你有两个选项 - 要么使用AIDL构建自定义接口,要么使用原始的transact()


但是,我该如何使用Intent传递Handler?有任何示例吗? - Milan
1
你需要那个处理程序做什么?你确定在服务中从头开始构建处理程序不会有帮助吗?服务不是线程;服务在与消费者代码相同的UI线程上执行。 - Seva Alekseyev
我不知道在这方面bindServicestartService是否有区别,但根据文档和这个讨论,当Intent在onBind中接收时,额外的参数可能不存在。 - DuneCat

2

Service继承自Context,因此您在构造函数中不需要将其作为参数,因为您可以使用同一实例。

如果您有其他要传递给服务的参数,我建议将它们作为extras添加到startService意图中,并在service.onStartCommand方法中获取它们。


再次问一下,如何通过意图传递处理程序? - Milan

2
intent service = new Intent(current context, your service name.class);
`service.putExtra(key,value);`// put your sightly variable type
`service.setAction("StartDownload");`// action that will detect in onStartCommand

 current context.startService(service);

在服务中的onStartCommand方法:

原始回答
if (intent.getAction().equals("StartDownload")) {
`intent.getExtras().getString(key)`;// string in this sample should be your variable type as you used in your code
//do what you want
    }`

0
你的Service类需要一个无参构造函数,否则系统不知道如何实例化它。

0

与其将Handler(或任何对象)传递给服务(顺便说一句,这是不可能的),您可以在Activity类中创建并注册BroadcastReceiver。当您需要调用Handler函数(或其他对象中的任何函数)时,请在已注册的接收器上发送广播(sendBroadcast)。您还可以将其他额外参数放入意图中,并根据参数直接从Activity处理所有所需代码。

也许,在这种情况下,您的处理程序将被完全删除(取决于您实际需要什么)。使用广播接收器,我不知道会出现需要将某些对象传递给服务的情况。另一方面,您正在做一些不好的事情,应该重新审查应用程序的设计。

如果我们想要将某些内容传递给服务,则只能使用Intent中的额外参数启动服务。服务根据这些参数处理状态。

这个想法是Service可以独立于应用程序的其他部分运行,例如Activities。我们可以通过启动服务时的额外参数或通过发送广播来控制它以调用外部代码。


0
不要将Handler传递给Service,因为Handler没有实现Parcelable或Serializable接口,所以我认为这是不可能的。
在Service中创建Handler,并通过Intent Extras将需要创建Handler所需的任何数据传递给Service。

0

这并不是关于如何解决你的问题,而是关于“如何使用构造函数实例化Android服务?”

正如到目前为止所提到的那样,在实际系统中由Android创建服务时,您必须避免为构造函数传递任何参数。

但是,当您想要自定义测试服务而又不想更改其代码时该怎么办呢?

仅仅作为测试目的,我解决了如下问题:

public class TestService extends YourService {
    TestService(Context context) {
        attachBaseContext(context);
    }
}

然后,只需使用MockContext实例、mock(Contex.class)甚至是扩展了Context的实例-contextInstance来创建它。

@Test
public void testCreateService() {
    TestService service = new TestService(contextInstance);
    service.onCreate();
    //service.onStart(...);// or service.onBind(...);
}

有了这个,来自YourService代码的上下文相关调用将被重定向到contextInstance,您可以根据需要处理它。 YourService的无参数构造函数在这里不是限制(用于测试目的),但拥有自己的上下文足以不必操纵服务的构造函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接