2012-02-20 44 views
12

我有一個綁定到持久服務的Android應用程序(一旦以startService()開始)。乾淨地綁定/解除綁定到應用程序中的服務

該服務是應用程序的組成部分,因此幾乎可用於每個活動。因此,我只想綁定到服務一次(而不是在每個活動中綁定/解除綁定),並在應用程序的生命週期中保持綁定。

我已從Application擴展並綁定到Application#onCreate()的服務。不過我現在已經當因爲Application#onTerminate()存在我的應用程序不會被調用,我不知道這個問題,看到的JavaDoc:

此方法是在模擬過程中的環境中使用。它不會在生產Android設備上調用 ,其中通過簡單地殺死進程來刪除進程 ;沒有用戶代碼(包括此回調)在執行此操作時執行 。

那麼我該如何幹淨地從應用程序中綁定的服務中解除綁定呢?

回答

12

我通過計算Application中對服務綁定的引用來解決此問題。每個Activity必須在其onCreate()方法中調用acquireBinding(),並在onDestroy()中調用releaseBinding()。如果參考計數器達到零,則釋放綁定。

下面是一個例子:

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

您的服務如何在屏幕旋轉中生存? – 2014-01-07 23:40:45

+1

你是什麼意思? Android中的服務沒有UI,因此它可以繼續運行。在這種情況下,Service先前使用'context.startService()'啓動,並被標記爲sticky,以便它運行直到它被手動停止或停止。 – 2014-01-08 09:28:29

+0

我明白了。我在想,釋放綁定會停止服務,但不是在這種混合服務的情況下。釋放綁定以避免泄漏的服務連接。 – 2014-01-08 20:44:30

4

從埃裏克森的回答:

我被引用計數在應用程序綁定服務 解決了這個問題。每個Activity都必須在其onCreate()方法中調用 acquireBinding(),並在onDestroy()中調用releaseBinding() 。如果參考計數器達到零,則發佈綁定爲 。

我同意,但你不應該在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檢查,我認爲你需要將onCreate中的acquireBinding()調用移動到onStart/onResume(取決於sdk版本),以確保你的ref count不會混亂。

誰知道釋放你的應用程序的服務將非常複雜!

+0

謝謝您的澄清。我會看看這個。我也有這樣的印象,即我的解決方案一直不可靠。 – 2012-04-11 10:40:13

2

在這種情況下,解綁是否必要?無論如何,應用程序都會被殺死我嘗試實現一個示例應用程序,而不是解除綁定,它似乎正常工作。

+0

如果您不解除綁定,應該在日誌中看到「泄露的服務連接」錯誤。 – 2012-11-24 11:18:42