Service簡析

簡介

Service作爲Android的四大組件之一,它的重要性不言而喻,之前雖說看過一些介紹但是一直沒有用過,最近需要用到的時候發現無從下手,便閱讀了官方的有關Service的Guide,這裏總結一下。

Service作用

官方介紹如下

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.

Service主要用於在後臺執行長期任務或者耗時操作,在需要的時候甚至可以在應用退出的時候保持運行狀態。

Service與Thread

雖說Service可以在後臺執行任務,但是實際上一個Service是運行在主線程的,如果有耗時操作我們必須在Service中自己開啓一個Thread避免ANR。那就會有這麼一個問題,我們爲什麼不用Thread呢?主要的原因就是Thread的可控性不好,假設我們在一個Activity中啓動了一個Thread,一旦這個Activity結束了,那麼其他的Activity就沒有辦法拿到這個Thread的引用,更別談控制了。可是Service不一樣,一個Service整個程序只會創建一個實例,而且任何Activity都可以控制,那麼Service裏的Thread就可以由所有Activity控制了。而且Service作爲四大組件之一,有較高級別,在後臺運行不容易被系統殺掉。

Service分類

Service分爲兩類

  • Started Service:不和其他組件通信
  • Bound Service:可以和其他組件通信

    無論使用哪一種Service都必須重寫onBind()方法,如果使用Started Service返回null就可以了。

使用Started Service

一般需要再重寫兩個方法

  • onCreate():啓動Service的時候並不存在該Service實例,就會調用該方法。
  • onStartCommand(Intent intent, int flags, int startId):每次通過startService(Intent intent)啓動的時候就會掉用該方法,一般在這裏開啓新線程。

onStartCommand(Intent intent, int flags, int startId)方法返回int類型的值,代表Service被kill後的行爲,有以下三種:

  • START_NOT_STICKY:表示不重新創建
  • START_STICKY:表示重新創建,調用onStartCommand傳入null
  • START_REDELIVER_INTENT:表示重建,調用onStartCommand傳入上一個Intent

爲了節省資源和電量,我們在任務結束後必須關閉Service,想要關閉Service可以通過本身調用stopSelf()或者其他組件調用stopService(),但是如果我們的Service處理多個onStartCommand請求的時候,我們在請求結束後掉用stopSelf()可能會打斷已經收到的新的請求,最好的情況就是我們本身就是最後一個請求,stopSelt(int)的一個參數的重載可以解決這個方法,傳入的id就是onStartCommand傳遞進來的id,代表當前任務的id,它會把傳入的id和最後一個id比較,如果一樣的話就代表本身是最後一個任務,就會stop掉,否則不會執行stop。

使用Bound Service

主要和Started Service的區別就是可以和其他組件通信,通過Binder。
創建時必須定義接口描述用戶如何與Server交流,接口必須繼承Binder。使用bindService()創建,必須提供一個ServiceConnection的實現,,bindService()是一個異步方法,立馬回返回。當創建完後會調用ServiceConnection的onServiceConnected,並傳遞binder通信。onBind方法只在第一個用戶連接調用,後來都返回同一個binder(因爲只會有一個Service),代碼如下

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();
    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }

bind service的代碼如下

private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
bindService(intent, mConnection, 0);

可以看出我們在Service中自定義了binder繼承自Binder,並聲明瞭一個方法,然後在onBind()中返回一個實例。我們會在onServiceConnected方法中得到這個binder,然後我們調用裏的方法得到Service的實例,這樣就可以掉用裏面方法了,也就完成了通信。bindServicer第三個參數是剛開始的選擇,如果是BIND_AUTO_CREATE表示如果沒啓動就新建

注意事項

onServiceDisconnected方法不是unbind的時候調用的,實在被kill等意外情況調用的

發佈了40 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章