Android:如何在销毁绑定服务时避免服务连接泄漏

时间:2015-01-03 23:18:38

标签: android service binding memory-leaks

我想请求帮助解决这个问题。这看起来很常见,但我没有在任何地方找到答案。它只提到here

我有一个服务A使用服务连接C绑定到第二个服务B.

  1. A正在运行并绑定到B
  2. B被停止并被销毁(没有错误状态 - 它通常会完成)
  3. 在C上调用onServiceDisconnected()
    • 我发现有些人提到这个问题并不正常。但是当B被摧毁时,我可以观察到它。
  4. 我现在该怎么办?
    • 根据guide,我什么都不做(因为B被破坏并断开连接)。但是当A被销毁时,这会导致服务泄漏异常,因为C仍处于活动状态!
  5. 所以我的问题是:错误在哪里?在我的场景或Google指南中。

    我尝试将A中的代码更改为以下形式,它看起来效果很好,但它很难看:

    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)
        {
            // I have to test mService, not mServiceConnection.bound
        }
    }
    

    有没有其他选项如何正确处理?非常感谢您的帮助或意见。

2 个答案:

答案 0 :(得分:0)

由于我没有足够的声誉对帖子发表评论,你是否考虑过使用烟斗? 通过这种方式,您可以在没有两项服务的情况下实现良好的沟通。

如果您想了解有关高效多线程的更多信息,建议您阅读本书:

Efficient multi threading in Android

并转到第39页第4章,这里有管道和连接东西的整章。

答案 1 :(得分:0)

所以我使用了我的问题中的方法并将其包装到SafeServiceConnection类中。我知道,在所有绑定都未绑定之前,服务通常不会被销毁,但并不总是需要行为。

public class SafeServiceConnection<T extends Service> implements ServiceConnection
{
    private final Logger log = new Logger(SafeServiceConnection.class);

    boolean mBound = false;
    T mService;

    @SuppressWarnings("unchecked")
    @Override
    final public void onServiceConnected(ComponentName name, IBinder service)
    {
        mService = ((ServiceBinder<T>) service).getService();

        if (mService == null)
        {
            return;
        }

        if (!mBound)
        {
            mBound = true;

            onServiceConnected(name, mService, true);
        }
        else
        {
            onServiceConnected(name, mService, false);
        }
    }

    public void onServiceConnected(ComponentName name, T service, boolean firstConnection)
    {

    }

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

    public void bind(Context context, Intent intent, int flags)
    {
        context.bindService(intent, this, flags);
    }

    public void bind(Context context, Intent intent)
    {
        bind(context, intent, Context.BIND_AUTO_CREATE);
    }

    public void startAndBind(Context context, Intent intent)
    {
        context.startService(intent);
        bind(context, intent);
    }

    public void unbind(Context context)
    {
        if (mBound)
        {
            if (context != null)
            {
                context.unbindService(this);
            }
            else
            {
                log.e("Context is null");
            }

            mBound = false;
        }
    }

    public T getService()
    {
        return mService;
    }

    public boolean isConnected()
    {
        return mService != null;
    }
}