干净地绑定/解除绑定到应用程序中的服务

时间:2012-02-20 16:03:45

标签: android service bind unbind

我有一个绑定到持久服务的Android应用程序(一旦以startService()开头)。

该服务是应用程序不可或缺的一部分,因此几乎在每个Activity中都使用。因此,我想只绑定一次服务(而不是在每个Activity中绑定/解除绑定)并在我的应用程序的生命周期内保持绑定。

我已从Application扩展并绑定到Application#onCreate()中的服务。但是我现在遇到的问题是我不知道我的应用程序何时存在,因为从未调用Application#onTerminate(),请参阅JavaDoc:

  

此方法适用于模拟过程环境。永远不会   在生产Android设备上调用,删除进程   简单地杀死他们;没有用户代码(包括此回调)   执行时执行。

那么如何从Application中绑定的服务中干净地取消绑定?

3 个答案:

答案 0 :(得分:13)

我通过计算Application中对服务绑定的引用来解决这个问题。每个Activity必须在acquireBinding()方法中调用onCreate(),并在releaseBinding()中致电onDestroy()。如果引用计数器达到零,则释放绑定。

以下是一个例子:

class MyApp extends Application {
    private final AtomicInteger refCount = new AtomicInteger();
    private Binding binding;

    @Override
    public void onCreate() {
        // create service binding here
    }

    public Binding acquireBinding() {
        refCount.incrementAndGet();
        return binding;
    }

    public void releaseBinding() {
        if (refCount.get() == 0 || refCount.decrementAndGet() == 0) {
            // release binding
        }
    }
}

// Base Activity for all other Activities
abstract class MyBaseActivity extend Activity {
    protected MyApp app;
    protected Binding binding;

    @Override
    public void onCreate(Bundle savedBundleState) {
        super.onCreate(savedBundleState);
        this.app = (MyApp) getApplication();
        this.binding = this.app.acquireBinding();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        this.app.releaseBinding();
    }
}

答案 1 :(得分:4)

来自Sven的回答:

  

我通过计算对服务的引用来解决这个问题   应用程序中的绑定。每个活动都必须打电话   在他们的onCreate()方法中的acquireBinding()并调用releaseBinding()   在onDestroy()中。如果引用计数器达到零,则绑定为   释放。

我同意,但你不应该在onDestroy中这样做 - 通常不会被调用。

相反,我建议以下内容(基于您的代码示例)...

// Base Activity for all other Activities
abstract class MyBaseActivity extend Activity {
    protected MyApp app;
    protected Binding binding;

    @Override
    public void onCreate(Bundle savedBundleState) {
        super.onCreate(savedBundleState);
        this.app = (MyApp) getApplication();
        this.binding = this.app.acquireBinding();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Pre-HC, activity is killable after this.
        if ((11 > Build.VERSION.SDK_INT) && (isFinishing()))
            onFinishing();
    }

    @Override
    protected void onStop() {
        super.onStop();
        if ((10 < Build.VERSION.SDK_INT) && (isFinishing()))
            onFinishing();
    }

    protected void onFinishing() {
        // Do all activity clean-up here.
        this.app.releaseBinding();          
    }
}

但是,我对isFinishing()的使用只是一个想法 - 我不确定它是否可靠。也许onPause / onStop使用isFinishing()调用false,但随后活动被杀死 - 而且你的releaseBinding()永远不会被调用。

如果你摆脱isFinishing检查,我认为你需要将acquireBinding()调用从onCreate移动到onStart / onResume(取决于sdk版本),以确保你的引用计数不会搞砸。

谁知道发布应用程序的服务会非常复杂!

答案 2 :(得分:2)

在这种情况下是否需要解除绑定?应用程序无论如何都会被杀死。我尝试在不解除绑定的情况下实现一个示例应用程序,它似乎正常工作。