Android:如何安全地取消绑定服务

时间:2011-12-23 09:34:24

标签: android

我有一个绑定到应用程序上下文的服务,如下所示:

getApplicationContext().bindService(
                    new Intent(this, ServiceUI.class),
                    serviceConnection,
                    Context.BIND_AUTO_CREATE
            );

protected void onDestroy() {
            super.onDestroy();                  
            getApplicationContext().unbindService(serviceConnection);
        }

由于某种原因,有时只有应用程序上下文没有正确绑定(我无法修复该部分),但是在onDestroy()中我执行unbindservice会抛出错误

java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection.

我的问题是:在解除绑定之前,有没有办法安全地调用unbindservice或检查它是否已绑定到服务?

提前致谢。

8 个答案:

答案 0 :(得分:64)

试试这个:

boolean isBound = false;
...
isBound = getApplicationContext().bindService( new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE );
...
if (isBound)
    getApplicationContext().unbindService(serviceConnection);

注意:

您应该使用相同的context来绑定服务并取消绑定服务。如果您使用getApplicationContext()绑定服务,那么您还应该使用getApplicationContext.unbindService(..)

答案 1 :(得分:7)

Here您可以找到一个很好的解释和源代码如何使用绑定服务。在您的情况下,您应该覆盖onServiceConnected对象的方法(onServiceDisconnectedServiceConnection)。然后,您只需检查代码中的mBound变量即可。

答案 2 :(得分:4)

确切地说安德烈诺维科夫提出的建议并不适用于我。 我只是替换了:

getApplicationContext().unbindService(serviceConnection);

使用:

unbindService(serviceConnection);

答案 3 :(得分:4)

我发现有两个问题。尝试绑定多次并尝试解除绑定多次。

解决方案:

public class ServiceConnectionManager implements ServiceConnection {

    private final Context context;
    private final Class<? extends Service> service;
    private boolean attemptingToBind = false;
    private boolean bound = false;

    public ServiceConnectionManager(Context context, Class<? extends Service> service) {
        this.context = context;
        this.service = service;
    }

    public void bindToService() {
        if (!attemptingToBind) {
            attemptingToBind = true;
            context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE);
        }
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        attemptingToBind = false;
        bound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        bound = false;
    }

    public void unbindFromService() {
        attemptingToBind = false;
        if (bound) {
            context.unbindService(this);
            bound = false;
        }
    }

}

答案 4 :(得分:0)

我认为guide并不完全正确[{3}} Surya Wijaya Madjid。当绑定服务被破坏且尚未重新连接时,可能会发生内存泄漏。

我认为需要采用这种方法:

Service mService;

private final ServiceConnection mServiceConnection = new ServiceConnection()
{
    boolean bound = false;

    @Override
    public void onServiceDisconnected(ComponentName name)
    {
        mService = null;
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service)
    {
        mService = ((MyService.ServiceBinder) service).getService();

        if (!bound)
        {
            // do some action - service is bound for the first time
            bound = true;
        }
    }
};

@Override
public void onDestroy()
{
    if (mService != null)
    {
        // do some finalization with mService
    }

    if (mServiceConnection.bound)
    {
        mServiceConnection.bound = false;
        unbindService(mServiceConnection);
    }
    super.onDestroy();
}

public void someMethod()
{
    if (mService != null)
    {
        // to test whether Service is available, I have to test mService, not     mServiceConnection.bound
    }
}

答案 5 :(得分:0)

为什么会出现此错误?

  

当您尝试注销未注册的服务时。

常见的例子有哪些?

  • 使用不同的上下文绑定和取消绑定服务。
  • 拨给unBind(mserviceConnection)的电话多于bind(...)

第一点是不言而喻的。让我们更深入地探讨错误的第二个来源。调试您的bind()和unbind()调用。如果您看到按此顺序的呼叫,则您的应用程序最终将获得IllegalArgumentException

enter image description here

如何避免这种情况?
您应该考虑两种方法来绑定和取消绑定Activity中的服务。 Android文档建议

  • 如果您仅想在活动可见时才与服务进行交互
  

onStart()中的bindService()和onStop()中的unbindService()

Your Activity {

    @Override
    public void onStart(){
       super.onStart();
       bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onStop(){
       super.onStop();
       unbindService(mConnection);
    }

} 
  • 如果您想与服务进行交互,即使活动处于后台,那么
  

onCreate()中的bindService()和onDestroy()中的unbindService()

Your Activity {

    @Override
    public void onCreate(Bindle sis){
       super.onCreate(sis);
        ....
        bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }         

}

答案 6 :(得分:0)

使用变量记录是否绑定到服务,如果变量为true,则取消绑定。

请参阅android官方示例:

http://androidxref.com/9.0.0_r3/xref/development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java#376

答案 7 :(得分:-1)

对上述所有答案都不确定,它似乎太复杂了,而这些都不符合我的问题。

一次只绑定/解除绑定一次,并且在unbind()调用时服务肯定是绑定的。不想泄漏任何东西,所以我只是确保我对bind()和unbind()调用使用相同的上下文,并且永久地解决了它!做这样的事情:

any_context.getApplicationContext().bind(...);

...

another_context.getApplicationContext().unbind(...);