Service

ref: 高效能執行緒

Android Performance Patterns

why use service?

  • 將元件的生命週期跟Thread的生命週期分開(在Thread結束前無法釋放物件導致Memory leak)。

  • 當一個Process內只剩下Thread在執行, 避免Process被系統意外回收, 導致Thread被提前結束。

Service生命週期

Service分成兩種類型

  • 被啟動的Service:由第一個元件啟動請求建立, 第一個元件停止請求銷毀。其間,啟動請求僅傳遞給該service。

    • 由start產生的service生命週期: onCreate → onStart\/onStartCommand → service is started → onDestroy → service is stopped

  • 被聯繫的Service:第一個元件Bind, 該Service此時被建立, 直到所有元件Unbind才銷毀。

    • 由bind產生的service生命週期: onCreate → onBind → service is bound → onUnbind → onDestroy → service is stopped

如果一個service在bind之後又進行start動作,在unbind之後,service還是會一直運作,直到stop動作被呼叫,service才會停止運行。反之,service先start,再bind的結果是一樣的。

  • 生命週期: onCreate -> onStart\/onStartCommand -> service is started -> onBind -> service is bound & is started -> unBind -> service is still running -> onDestroy -> service is stopped 或者: onCreate -> onBind -> service is bound -> onStart\/onStartCommand -> service is started & is bound -> unBind -> service is still running -> onDestroy -> service is stopped

1. 啟動(Start)的Service

public class ServiceDemo extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override public IBinder onBind(Intent intent) {
        return null;
    }
 }
  • 啟動的service非常簡單, 只要覆寫onBind並且回傳null, 接著再多覆寫onStartCommand, 將Thread寫進此方法即可。

  • 透過startService以及stopService控制啟動即結束, 也可以透過Service.stopSelf自行結束。

Service重啟

  • START_STICKY:Service被殺掉,系統會重啟,但是Intent會是null。

  • START_NOT_STICKY:Service被系統殺掉,不會重啟。

  • START_REDELIVER_INTENT:Service被系統殺掉,重啟且Intent會重傳。

2. 連繫(Bind)的Service

  • 常用在IPC( Inter Process Communication ),亦指程序間的溝通技術。一般常見通用的有Socket、資料庫、檔案等。
  • 透過Binder綁定機制進行遠端呼叫,並使用AIDL(Android Interface Definition Language)介面機制。
  • bindService()和unbindService()控制 連結 或 取消 連結 service。

    更多說明,可參考
    ref:http://www.juwends.com\/tech\/android\/android-service-2.html

注意!

Service和UI沒有關連,所以Service的create、execute、stop service都需要佔用系統時間和memory空間。另外Android預設Service是在UI Thread中執行,所以這表示Service可能會影響到系統的流暢度。

使用Service應遵循以下規則:

  • 避免誤用Service。

    • 例如:不該用 Service 監聽某些事件的變化, 不應該使用Service在background對服務器不斷的進行輪詢(polling)→應該使用Google Cloud Messaging。
  • 如果已經事先知道Service裡面的任務應該執行在Background Thread(非默認的主線程)的時候,我們應該優先使用IntentService或者結合HanderThreadAsycnTask Loader實現的Service

Android系統為我們提供了以下的一些非同步( Asynchronous )執行相關的工具包:

  • GCM
  • BroadcastReciever
  • LocalBroadcastReciever
  • WakefulBroadcastReciver
  • HandlerThreads
  • AsyncTaskLoaders
  • IntentService

如果使用上面的諸多方案還是無法替代普通的Service,那麼需要注意的就是如何正確的關閉Service。

IntentService vs. Service

  • Service

    • 由Client端控制,User自行控制啟動跟結束。

    • 並行任務執行:啟動多個Thread。

    • 循序且可以重新安排的任務:任務可以被賦予優先權 e.g. 音樂服務。

  • IntentService

    • 循序執行。

Foreground Service

這不能照字面翻譯(前景Service),不是工作在前景的Service。一般在Service運行在背景時,使用者無法得知此Service正運行背景。於是,開發者可透過 Foreground Service 所提供的機制 - Notification,通知使用者目前有正在運行的背景服務,這也是Android官方推薦的方法。而這種方法也可以讓系統在記憶體不足時,不會優先被系統給kill掉(通常被砍掉是看不到的背景服務)。

使用方法很簡單,在service啟動時,建立一個 Notification 並呼叫 startForeground() method即可;停止使用:呼叫 stopForeground() method 。

Notification notification = new Notification(R.drawable.icon,
                                             getText(R.string.ticker_text),
                                             System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
                                getText(R.string.notification_message),
                                pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
public final void startForeground (int id, Notification notification)  // id不能為0
public final void stopForeground (boolean removeNotification)  //如要從前景移除服務,可以呼叫 stopForeground()。
                                                               //此方法有一個boolean,表示是否同時移除狀態列通知。
                                                               //此方法「不會」停止服務。 
                                                               //然而,如果您在服務仍於前景執行時停止服務,則也會移除通知。
  • 如果可以獲得系統權限的話, 也可以在AndroidManifest.xml的application增加 android:persistent="true" 如此一來也可以盡可能避免service被系統kill掉。

results matching ""

    No results matching ""