Android Service可以在不启动的情况下绑定吗?

6

在我所阅读的许多文章、教程和文档中,我们经常看到调用startService()或bindService()函数的方式来启动服务。虽然两者都可以使用,但它们的使用场景不同。在没有调用startService()函数时,我无法使用bindService()函数。

    private void bindTunManagerService(int flags) {
    TunnelManagerService.setParentActivity(this);
    Intent bindIntent = new Intent(this, TunnelManagerService.class);
    startService(bindIntent);
    tunManagerServiceStarted = bindService(bindIntent, tunConnection, BIND_AUTO_CREATE);

    Log.d(TAG, "tunManagerServiceStarted  : " + tunManagerServiceStarted + ", ** tunManagerService = " + tunManagerService );

在上述代码中,如果我注释掉 startService(),bindService 将返回 false,并且 tunManagerService = null,即使 onServiceConnected 也没有被触发,我会收到“无法启动服务意图{...}未找到”的消息。添加 startService 后,服务的 onCreate、onStart 和 onServiceConnected 被调用并成功绑定。
在实际使用中,是否有必要先 startService,然后才能 bindService?这意味着如果没有 startService,我们就无法绑定 Service!如果这个说法是错误的,为什么我不能在不启动它的情况下绑定 Service?
有什么想法吗?
代码已添加:
ServiceConnection:
    private ServiceConnection tunConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(TAG,"onServiceConnected" );
        tunManagerService = ITunnelManagerService.Stub.asInterface(service);
        doConnect();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(TAG,"onServiceDisconnected" );
        tunManagerService = null;
    }

};

服务 :

public class TunnelManagerService extends Service {
@Override
public IBinder onBind(Intent arg0) {
    return binder;
}

@Override
public void onCreate() {
    super.onCreate();
    Log.d(TAG, "TunnelManagerService: onCreate");
    setCreatedPreference(true);
    notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG, "Received start id " + startId + ": " + intent);
    return START_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    setCreatedPreference(false);
    hideNotifConnected();
    Log.d(TAG, "TunnelManagerService: onDestroy");
}

private final ITunnelManagerService.Stub binder = new ITunnelManagerService.Stub() {
  // contains all methods
}

...............
.............

}

Manifest :

        <activity android:name=".StartUltimate" android:label="@string/app_name" 
         android:launchMode="singleTask" android:windowSoftInputMode="stateHidden|adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service android:name="orange.android.vpn.utilities.TunnelManagerService" android:enabled="true"></service>

我使用的是2.3.3 SDK,即API 10。我的活动从"orange.android.vpn"中调用,与服务相关的文件分别在"orange.android.vpn.utilities"包中。


你使用哪个API级别?在2.1上,我成功地实现了这种行为。 - Vladimir Ivanov
2
请发布您的Service和ServiceConnection代码。您是否查看了logcat输出?它是否显示任何错误?如果有,请在此处也发布。 - Mark Allison
可能是https://dev59.com/TXA75IYBdhLWcg3wKluM的重复问题。 - jakebasile
已添加Service和ServiceConnection代码。在logcat中,我只收到ActivityManager的“无法启动服务Intent {..<full path>..}未找到”警告。没有其他异常或错误。 - Tvd
请问您能否添加您的清单文件吗?谢谢。 - Mark Allison
显示剩余2条评论
2个回答

8
我找到了解决方案,现在与大家分享。有两种类型的服务:一种是启动和停止的,这种服务只能在应用程序中启动和停止一次。另一种是按需绑定和解绑N次的服务。我的服务属于第二种类型。但仅仅绑定和解绑还不够。服务首先需要启动,然后才能绑定和解绑。所以在应用程序启动时或适当的地方,先启动服务。然后在需要时进行绑定。完成后,解绑它。这个绑定-解绑循环可以一直进行。最后,在你确定不再需要它或在应用程序结束时,停止服务。因此,流程如下: 启动 -> 绑定 -> 解绑 -> 停止 <-

5
@ Jason:是的,但有些关键的事情可能是在服务的onStartCommand方法中完成的。我现在正在使用一个服务,发现只有在显式启动服务时才能正常工作。这也是Tvd解决方案的解释。 - DuneCat
10
这似乎不是答案。 您应该能够绑定服务而无需显式启动它。 如果您还想在绑定时启动它:绑定服务并传递标志Context.BIND_AUTO_CREATE。 - ZiviMagic
1
引用:“当一个服务从所有客户端解除绑定时,Android系统会销毁它(除非它还使用onStartCommand()启动)”,请参见http://developer.android.com/guide/components/bound-services.html#Lifecycle。 - Dori
如果我的工作线程只在onCreate()中绑定而没有onStartCommand(),那我应该从哪里开始呢? - JohnyTex
2
这是一个误导性的回答。一个服务可以通过调用bindService并传递BIND_AUTO_CREATE标志来启动。因为你的回答,我以为服务在绑定之前总是需要先启动。但是后来我自己尝试了一下,发现不需要显式地调用startService()也可以进行绑定。请修改你的回答,以免误导其他人。 - thedarkpassenger
显示剩余2条评论

6
是的。
bindService(new Intent(this, MyService.class), mConnection, 0);

据我所知,只要MyService没有问题,这个语句将始终返回true。
具有以下两种情况:
1.服务以前已启动——调用mConnection的onServiceConnected()方法
2.服务尚未启动——mConnection的onServiceConnected()方法未被调用且服务未启动。但是,只要服务被其他方式启动,onServiceConnected()方法就会被调用。
实际上,在调用此方法时,我假设服务在onServiceConnected()方法被调用之前未启动。

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