Cleanly binding/unbinding to a Service in an Application

旧时模样 提交于 2019-12-02 20:52:49

I solved this problem by counting the references to the service binding in the Application. Every Activity has to call acquireBinding() in their onCreate() methods and call releaseBinding() in onDestroy(). If the reference counter reaches zero the binding is released.

Here's an example:

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();
    }
}

From Sven's answer:

I solved this problem by counting the references to the service binding in the Application. Every Activity has to call acquireBinding() in their onCreate() methods and call releaseBinding() in onDestroy(). If the reference counter reaches zero the binding is released.

I agree, BUT you shouldn't do it in onDestroy - that will often not get called.

Instead I suggest the following (based on your code sample)...

// 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();          
    }
}

BUT, my use of isFinishing() is just a thought - I'm not certain that it is reliable. Perhaps onPause/onStop get called with isFinishing() false, but then the activity gets killed - and your releaseBinding() never gets called.

If you get rid of the isFinishing check I think you need to move the acquireBinding() call from onCreate to onStart/onResume (depending on sdk version), to ensure that your ref count doesn't get messed up.

Who knew that releasing your app's service would be so complicated!

Is unbinding necessary at all in this case? The application gets killed anyway. I tried implementing a sample application doing this without unbinding and it seems to work properly.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!