Service 理解和兩種啟動方式

Service 理解

Service是什么?

Service 作為android系統的四大組件之一,是一種可以在后臺長時間運行操作而沒有用戶界面的應用組件。

Service和Thread的區別

1、Thread是程序運行的最小單位即線程,可以執行異步長時間耗時的操作。

2、Service是android中的組件,是運行在主線程上的,是要依托android程序運行的,所以不能做耗時操作。

Service android是四大組件之一。Service 是一個抽象類,我們需要些一個自定義Service繼承于Service。

啟動方式

Service 的啟動方式有兩種,一種是startService(),一種是bindService().這兩種方式有有什么區別.

  • startService(),啟動完之后該service就在后臺運行,其生命周期跟啟動它的Context沒有任何關系。也不能跟Context通訊。
  • bindService()啟動之后生命周期跟啟動它的Context有關,比如Activity、fragment、service等。在Context中解綁之后,如果改Service沒有任何綁定后該Service也就結束。

生命周期

Service 的生命周期跟啟動方式有關。

stratService的生命周期: onCreate() -> onStartCommand() -> onDestroy()

startService.png

bindService的生命周期: onCreate() -> onBind() -> onUnbind() -> onDestroy()

bindservice.png

startService

用startService 方式啟動Service的時候重寫onStartCommand()的方法。每次用該方式啟動Service的時候都會調用改方法。

返回值是一個int類型的:

  • START_STICKY: 當Service因內存不足而被系統kill后,一段時間后內存再次空閑時,系統將會嘗試重新創建此Service,一旦創建成功后將回調onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個狀態下比較適用于不執行命令、但無限期運行并等待作業的媒體播放器或類似服務。
  • START_NOT_STICKY:當Service因內存不足而被系統kill后,即使系統內存再次空閑時,系統也不會嘗試重新創建此Service。除非程序中再次調用startService啟動此Service,這是最安全的選項,可以避免在不必要時以及應用能夠輕松重啟所有未完成的作業時運行服務。
  • START_REDELIVER_INTENT:當Service因內存不足而被系統kill后,則會重建服務,并通過傳遞給服務的最后一個 Intent 調用 onStartCommand(),任何掛起 Intent均依次傳遞。
  • START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill后一定能重啟。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    String test = intent.getStringExtra("test");
    LogHelper.i("-------test-------" + test);
    LogHelper.i("-------flags-------" + flags);
    LogHelper.i("-------startId-------" + startId);
    LogHelper.i("-------onStartCommand-------");

    return super.onStartCommand(intent, flags, startId);
}

這里的參數是:

  • intent: 啟動時,啟動組件傳遞過來的Intent,如Activity可利用Intent封裝所需要的參數并傳遞給Service。
  • flags: 表示啟動請求時是否有額外數據,可選值有 0,START_FLAG_REDELIVERY,START_FLAG_RETRY,0代表沒有.START_FLAG_REDELIVERY: 這個值代表了onStartCommand方法的返回值為START_REDELIVER_INTENT,意味著當Service因內存不足而被系統kill后,則會重建服務,并通過傳遞給服務的最后一個 Intent 調用 onStartCommand()。START_FLAG_RETRY : 該flag代表當onStartCommand調用后一直沒有返回值時,會嘗試重新去調用onStartCommand()。
  • startId:指明當前服務的唯一ID,與stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根據ID停止服務。

startService的完整Service:

public class SimpleService extends Service {

    /**
     * 綁定服務時才會調用,必須要實現的方法
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * Called by the system when the service is first created.
     * 首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。
     * 如果服務已在運行,則不會調用此方法。該方法只被調用一次
     */
    @Override
    public void onCreate() {
        super.onCreate();
        LogHelper.i("-------onCreate-------");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String test = intent.getStringExtra("test");
        LogHelper.i("-------test-------" + test);
        LogHelper.i("-------flags-------" + flags);
        LogHelper.i("-------startId-------" + startId);
        LogHelper.i("-------onStartCommand-------");

        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 服務銷毀時的回調
     */
    @Override
    public void onDestroy() {

        LogHelper.i("-------onDestroy-------");
        super.onDestroy();
    }
}

調用也就是簡單的startService:

mStart.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(ServiceActivity.this,SimpleService.class);
        intent.putExtra("test","數據傳輸");
        startService(intent);
    }
});

mEnd.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(ServiceActivity.this,SimpleService.class);
        stopService(intent);
    }
});

bindService

bindService 的方式啟動Service,其作用是該Service可以和啟動它的Context(Activity等)進行通訊。其是ServiceConnection()的接口方法和服務器交互,在綁定即onBind()的時候回調。在這個方法中獲取Service傳遞過來的IBinder對象,通過這個對象實現跟宿主交互。

BindService的Service:

public class BindService extends Service {

    private LocalBinder mBinder = new LocalBinder();
    private Thread mThread;
    private int count;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        LogHelper.i("------onBind-----");
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        LogHelper.i("------onCreate-----");
        mThread = new Thread(new Runnable() {
            @Override
            public void run() {
               while (true){
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   count++;
               }
            }
        });
        mThread.start();
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogHelper.i("------onDestroy-----");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        LogHelper.i("------onUnbind-----");
        return super.onUnbind(intent);
    }

    public int getCount(){
        return count;
    }

    /**
     * 創建Binder對象,為后面給綁定的Activity使用。
     */
    public class LocalBinder extends Binder {
        /**
         * 提供一個方法,返回當前對象LocalService,這樣我們就可在客戶端端調用Service的公共方法了
         * @return
         */
        BindService getService(){
            return BindService.this;
        }
    }
}

調用的方式:先創建ServiceConnection:

mConn = new ServiceConnection(){
    /**
     * 與服務器端交互的接口方法 綁定服務的時候被回調,在這個方法獲取綁定Service傳遞過來的IBinder對象,
     * 通過這個IBinder對象,實現宿主和Service的交互。
     */
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        LogHelper.i("---綁定成功.---");
        BindService.LocalBinder binder = (BindService.LocalBinder)service;
        mBindService = binder.getService();
    }

    /**
     * 當取消綁定的時候被回調。但正常情況下是不被調用的,它的調用時機是當Service服務被意外銷毀時,
     * 例如內存的資源不足時這個方法才被自動調用。
     */
    @Override
    public void onServiceDisconnected(ComponentName name) {
        LogHelper.i("---取消綁定.---");
        mBindService = null;
    }
};

//綁定啟動Service.
mStart.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(BindServiceActivity.this,BindService.class);
        bindService(intent,mConn, Service.BIND_AUTO_CREATE);
    }
});

//解綁Service 
mEnd.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if(mBindService != null){
            mBindService = null;
            unbindService(mConn);
        }
    }
});


//通過IBinder獲取Service對象,然后訪問Service的public方法。
mGet.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if(mBindService != null){
            int count = mBindService.getCount();
            LogHelper.i("-------count--------" + count);
            mText.setText("---" + count);
        }else {
            LogHelper.i("-------service 未綁定--------");
        }

    }
});

區別

調用方式不同;

startService

使用Service的步驟:

1.定義一個類繼承Service
2.在Manifest.xml文件中配置該Service
3.使用Context的startService(Intent)方法啟動該Service
4.不再使用時,調用stopService(Intent)方法停止該服務

使用這種start方式啟動的Service的生命周期如下:
onCreate()--->onStartCommand()onStart()方法已過時) ---> onDestory()

說明:如果服務已經開啟,不會重復的執行onCreate(), 而是會調用onStart()onStartCommand()。
服務停止的時候調用 onDestory()。服務只會被停止一次。

特點:一旦服務開啟跟調用者(開啟者)就沒有任何關系了。開啟者退出了,開啟者掛了,服務還在后臺長期的運行。開啟者不能調用服務里面的方法。

bindService

使用Service的步驟:

1.定義一個類繼承Service
2.在Manifest.xml文件中配置該Service
3.使用Context的bindService(Intent, ServiceConnection, int)方法啟動該Service
4.不再使用時,調用unbindService(ServiceConnection)方法停止該服務作者:

使用這種start方式啟動的Service的生命周期如下:
onCreate() --->onBind()--->onunbind()--->onDestory()

注意:綁定服務不會調用onstart()或者onstartcommand()方法

特點:bind的方式開啟服務,綁定服務,調用者掛了,服務也會跟著掛掉。
綁定者可以調用服務里面的方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,067評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,467評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,468評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,184評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,582評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,794評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,343評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,096評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,291評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,513評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,941評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,190評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,026評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,253評論 2 375

推薦閱讀更多精彩內容