Android學習筆記2 四大組件之Service

四大組件中奈附,我們最熟悉的而且最常用的應(yīng)該是Activity了,它的主要作用是提供用戶交互的界面煮剧,那么如果有一些任務(wù)只需要在后臺執(zhí)行而不需要界面斥滤,那應(yīng)該怎么辦呢。今天總結(jié)歸納的是Service勉盅。

目錄
一佑颇、Service概述
二、Service的基本用法
   1.啟動Service
   2.綁定Service
三草娜、Service生命周期
四挑胸、Service的幾點說明
五、IntentService使用
六宰闰、相關(guān)參考

一茬贵、概述

首先我們看下官方對Service的介紹:

Service是一個可以在后臺執(zhí)行需要長時間運行的操作的應(yīng)用組件,它沒有用戶界面移袍。其它組件可以啟動一個Service解藻,之后即使用戶切換到別的應(yīng)用里,這個Service也將繼續(xù)在后臺運行葡盗。此外舆逃,一個組件可以與一個Service綁定來與之交互,甚至可以執(zhí)行IPC進程間通信。服務(wù)可以在后臺執(zhí)行很多任務(wù)路狮,比如處理網(wǎng)絡(luò)事務(wù)虫啥,播放音樂,文件讀寫或者與一個內(nèi)容提供者交互奄妨,等等涂籽。

Service主要有兩種形式:啟動狀態(tài)和綁定狀態(tài)。

啟動狀態(tài)(Started)

當一個應(yīng)用組件比如activity通過調(diào)用startService()來啟動一個服務(wù)的時候砸抛,服務(wù)便處于啟動狀態(tài)评雌。一旦啟動,服務(wù)可以在后臺無限期地運行下去直焙,即使當啟動它的組件已經(jīng)銷毀景东。通常情況下,一個啟動的service執(zhí)行一個單一的操作并且不會返回任何結(jié)果給調(diào)用者奔誓。例如斤吐,服務(wù)可能通過網(wǎng)絡(luò)下載或者上傳一個文件,當操作完成厨喂,服務(wù)會自己停止和措。

綁定狀態(tài)(Bound)

當一個應(yīng)用組件通過調(diào)用bindService()來與一個服務(wù)綁定時,服務(wù)便處于綁定狀態(tài)蜕煌。一個綁定的服務(wù)提供了一個客戶端-服務(wù)器端接口來允許組件與服務(wù)進行交互派阱,發(fā)送請求,得到結(jié)果甚至通過IPC進程間通信來完成操作斜纪。只有當其它組件與服務(wù)綁定時贫母,服務(wù)才會處于綁定狀態(tài)。多個組件可以同時與服務(wù)綁定盒刚,但是當他們?nèi)慷冀獬壎〞r颁独,服務(wù)就會銷毀。

二伪冰、Service的基本用法

對于Activity的使用誓酒,我們應(yīng)該都比較熟悉了,一般是先新建一個繼承Activity的自己的Activity贮聂,然后在里面寫自己的邏輯靠柑,如果要啟動一個Activity的話可以通過調(diào)用StartActivity()傳入一個Intent對象來完成,在清單文件里進行Activity注冊也是必不可少的一步吓懈。與之類似歼冰,Service基本用法也很簡單,下面簡單介紹啟動Service的步驟耻警,之后會有詳細的介紹隔嫡。

啟動Service

  1. 新建Service
public class TestService extends Service {

    private final String TAG = "TestService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "---onCreate()---");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "---onStartCommand()---");
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "---onDestroy()---");
    }
}
  1. 注冊Service


    清單文件里注冊Service.png

3.啟動Service

點擊按鈕后啟動Service

從上面這張圖可以看到甸怕,新建一個Intent對象并把它傳給startService,這樣就可以啟動一個Service了腮恩,啟動Service后如果想要停止它梢杭,可以使用stopService方法。

停止Service.png

綁定Service

下面是組件與Service綁定的步驟秸滴。

  1. 首先我們修改一些之前的Service.
public class TestService extends Service {

    private final String TAG = "TestService";

    //實例化"粘合劑" 可返回給與Service綁定的組件
    private MyBinder mMyBinder = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "---onCreate()---");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "---onStartCommand()---");
        return super.onStartCommand(intent, flags, startId);
    }

    //綁定后調(diào)用此方法
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return mMyBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "---onDestroy()---");
    }

    //這里執(zhí)行任務(wù)
    public class MyBinder extends Binder {
        public void startTask() {
            Log.i(TAG, "Task starts...");
        }
    }
}

2.假設(shè)我們要在一個Activity里通過點擊一個按鈕來綁定Service武契,那么我們要先在Activity里新建一個ServiceConnection的實例。下面代碼是在Activity里抽取出來的荡含。

    private TestService.MyBinder mMyBinder;

    /**
     * 服務(wù)連接
     */
    private ServiceConnection mServiceConnection = new ServiceConnection() {

        /**
         * 當服務(wù)連接后 返回binder
         * @param name
         * @param binder
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            mMyBinder = (TestService.MyBinder) binder;
            mMyBinder.startTask();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }

    };

3.這樣我們在Activity里點擊一個按鈕來綁定Service的時候咒唆,可以調(diào)用BindService來完成,詳細如下圖释液。

綁定Service

啟動后的Service可以用stopService來停止服務(wù)全释,綁定后的Service可以用unbindService來取消綁定。

取消綁定

Service用法小結(jié)

  1. 上面的基本用法其實展示了Service最基本的用法误债,包括啟動Service浸船,停止Service,綁定Service以及取消綁定Service找前,Service里的邏輯很簡單,實際上在平時的開發(fā)過程中判族,在后臺執(zhí)行時應(yīng)該會比較復(fù)雜躺盛,考慮的東西也比較多。

  2. 啟動Service的邏輯其實比較簡單形帮,就是新建一個Intent對象槽惫,然后調(diào)用startService方法把對象傳進去,之后就可以啟動了辩撑,停止的時候也是傳一個Intent對象給stopService方法界斜。

  3. 綁定Service的話邏輯較為復(fù)雜,這里我們是將Activity與Service建立綁定合冀。我們可以看到幾點注意事項:
    (1) 首先是在Service里各薇,我們定義了一個繼承Binder的子類,用來執(zhí)行任務(wù)君躺,Binder我覺得可以理解為"粘合劑"峭判,我們可以理解為它是其它組件和Service的之間的結(jié)合物,之后實例化這個Binder并在回調(diào)方法里返回這個Binder給綁定Service的組件棕叫,就可以通過它讓組件控制Service了林螃。
    (2) 然后是在Activity里實例化了一個ServiceConnection,并重寫了onServiceConnected方法俺泣,這個方法會在建立連接后返回Service的Binder疗认,然后通過Binder執(zhí)行Service里的任務(wù)完残。
    (3) 綁定Service的時候,調(diào)用bindService方法横漏,這里傳入三個參數(shù)谨设,一個是Intent對象,說明要與哪個Service綁定绊茧,一個是剛才的ServiceConnection實例铝宵,第三個參數(shù)是常量,我們這里傳入BIND_AUTO_CREATE华畏,表示綁定時是否自動創(chuàng)建Service鹏秋。

  4. 銷毀綁定的Service的時候只需要在使用unbindService方法時傳入?yún)?shù)ServiceConnection實例即可。

  5. 如果既點擊了Start Service按鈕亡笑,又點擊了Bind Service按鈕侣夷,這樣的話不管是單獨點擊Stop Service按鈕還是Unbind Service按鈕,Service都不會被銷毀仑乌,必要將兩個按鈕都點擊一下百拓,Service才會被銷毀。也就是說晰甚,點擊Stop Service按鈕只會讓Service停止衙传,點擊Unbind Service按鈕只會讓Service和Activity解除關(guān)聯(lián),一個Service必須要在既沒有和任何Activity關(guān)聯(lián)又處理停止狀態(tài)的時候才會被銷毀厕九。

三蓖捶、Service生命周期

Service的生命周期比Activity的簡單很多,但是更加要引起重視扁远,畢竟Service可能是在用戶不知情的情況下在后臺運行的俊鱼。下面這張圖很清楚地為我們展示了兩種不同的方式,Service的生命周期畅买。

Paste_Image.png

看這張圖并闲,我們可以初步對Service之前的幾個回調(diào)方法有所了解,啟動和綁定Service都會調(diào)用onCreate()方法來創(chuàng)建Service谷羞,如果是啟動的話會調(diào)用onStartCommand()方法帝火,如果是綁定的話會調(diào)用onBind()方法,當啟動的Service停止后會調(diào)用onDestroy()方法銷毀湃缎,綁定的Service在全部都解除綁定后調(diào)用onUnbind()方法购公,最后調(diào)用onDestroy()方法銷毀。

四雁歌、Service的幾點說明

  1. A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.Service不是一個單獨的進程宏浩,Service與它所在應(yīng)用位于同一進程中。

  2. A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).Service不是一個線程靠瞎,所以為了避免ANR錯誤(用戶無響應(yīng))比庄,我們應(yīng)該在Service里開啟新的線程來處理耗時任務(wù)求妹。

  3. 我們可以看到Service只是一個在后臺運行的沒有用戶界面的組件,使用它做些耗時的任務(wù)時佳窑,是需要開啟新線程的制恍。這里如果有需要的話,可以詳細去了解下IntentService這個類神凑,它可以很方便地處理一些多線程問題净神。

五、IntentService

Service這個組件默認情況下仍然運行在應(yīng)用的主線程中溉委,所以如果我們要執(zhí)行耗時或者阻塞操作鹃唯,那么為了避免ANR,應(yīng)該要在Service內(nèi)創(chuàng)建一個新的線程瓣喊。IntentService是Service類的一個子類坡慌,用來處理異步請求。

下面是一個IntentService使用示例:

//實現(xiàn)倒計時5秒的服務(wù)

public class MyIntentService extends IntentService {

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public MyIntentService() {
        super("count down 5");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("ssssss", "倒計時服務(wù)創(chuàng)建...");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        long endTime = System.currentTimeMillis() + 5 * 1000;

        while (System.currentTimeMillis() < endTime) {
            synchronized (this) {
                try {
                    wait(endTime - System.currentTimeMillis());
                } catch (Exception e) {
                } finally {
                    Log.e("ssssss", "倒計時結(jié)束...");
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("ssssss", "倒計時服務(wù)銷毀...");
    }
}


與普通Service一樣藻三,我們可以通過startService(Intent)方法傳遞請求給IntentService洪橘。通過查看源碼可知,IntentService在onCreate()函數(shù)中通過HandlerThread單獨開啟一個線程來處理所有Intent請求對象所對應(yīng)的任務(wù)棵帽,這樣以免事務(wù)處理阻塞主線程熄求。執(zhí)行完所一個Intent請求對象所對應(yīng)的工作之后,如果沒有新的Intent請求達到逗概,則自動停止Service弟晚;否則執(zhí)行下一個Intent請求所對應(yīng)的任務(wù)。

IntentService詳解

官方建議我們使用IntentService來完成異步請求的處理仗谆,那么IntentService內(nèi)部具體都做了哪些東西呢指巡?大概如下:

  1. 創(chuàng)建一個獨立于應(yīng)用主線程的新的線程來執(zhí)行所有傳遞給onStartCommand()方法中的請求淑履。

  2. 創(chuàng)建一個工作隊列隶垮,一次傳遞一個請求到onHandleIntent()方法中。

  3. 當所有請求處理完成后秘噪,停止服務(wù)狸吞,不需要我們手動調(diào)用stopSelf()。

  4. 提供onBind()方法的默認實現(xiàn)指煎,并且返回空蹋偏。

  5. 幫我們實現(xiàn)了將請求從onStartCommand()傳遞到工作隊列,然后傳遞到onHandleIntent()至壤。

為了對比地看出Service和IntentService在使用上的區(qū)別威始,下面展示一個使用Service的例子:


public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

六、相關(guān)參考

  1. Service基本使用
    Android Service完全解析像街,關(guān)于服務(wù)你所需知道的一切(上)

  2. Service高級用法
    Android Service完全解析黎棠,關(guān)于服務(wù)你所需知道的一切(下)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晋渺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子脓斩,更是在濱河造成了極大的恐慌木西,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件随静,死亡現(xiàn)場離奇詭異八千,居然都是意外死亡,警方通過查閱死者的電腦和手機燎猛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門恋捆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扛门,你說我怎么就攤上這事鸠信。” “怎么了论寨?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵星立,是天一觀的道長。 經(jīng)常有香客問我葬凳,道長绰垂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任火焰,我火速辦了婚禮劲装,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昌简。我一直安慰自己占业,他們只是感情好,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布纯赎。 她就那樣靜靜地躺著谦疾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪犬金。 梳的紋絲不亂的頭發(fā)上念恍,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音晚顷,去河邊找鬼峰伙。 笑死,一個胖子當著我的面吹牛该默,可吹牛的內(nèi)容都是我干的瞳氓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼栓袖,長吁一口氣:“原來是場噩夢啊……” “哼匣摘!你這毒婦竟也來了锅锨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤恋沃,失蹤者是張志新(化名)和其女友劉穎必搞,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囊咏,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡恕洲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了梅割。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霜第。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖户辞,靈堂內(nèi)的尸體忽然破棺而出泌类,到底是詐尸還是另有隱情,我是刑警寧澤底燎,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布刃榨,位于F島的核電站,受9級特大地震影響双仍,放射性物質(zhì)發(fā)生泄漏枢希。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一朱沃、第九天 我趴在偏房一處隱蔽的房頂上張望苞轿。 院中可真熱鬧,春花似錦逗物、人聲如沸搬卒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽契邀。三九已至,卻和暖如春莲祸,著一層夾襖步出監(jiān)牢的瞬間蹂安,已是汗流浹背椭迎。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工锐帜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畜号。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓缴阎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親简软。 傳聞我的和親對象是個殘疾皇子蛮拔,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容

  • [文章內(nèi)容來自Developers] Service是一個可以在后臺執(zhí)行長時間運行操作而不提供用戶界面的應(yīng)用組件述暂。...
    岳小川閱讀 864評論 0 7
  • 服務(wù)基本上分為兩種形式 啟動 當應(yīng)用組件(如 Activity)通過調(diào)用 startService() 啟動服務(wù)時...
    pifoo閱讀 1,270評論 0 8
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-androi...
    eddy_wiki閱讀 3,263評論 0 20
  • 思 文/迷戀深秋 霧蒙蒙 青山碧水迷霧間 可人兒 可辨得出那綠的模樣 路漫漫 蜿蜒陡峭云深處 可人兒 可記得那回家...
    迷戀深秋閱讀 246評論 0 1