Android四大組件之Service

Android四大組件之Activity
Android四大組件之Service
Android四大組件之BroadcastReceiver
Android四大組件之ContentProvider

Service

Service(服務(wù))是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不使用用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動(dòng),而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行。 此外,組件可以綁定到服務(wù),以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)。 例如,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)、播放音樂(lè),執(zhí)行文件 I/O 或與內(nèi)容提供程序交互,而所有這一切均可在后臺(tái)進(jìn)行。

一、創(chuàng)建Service

直接定義一個(gè)類(lèi),繼承自Service,和activity一樣,也要在AndroidManifest.xml中配置該Service。代碼如下:

public class MyService extends Service{

    //綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

AndroidManifest.xml中配置如下:

 <application
          <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--這里需要注意的是,service的配置也是在application標(biāo)簽中-->
        <service android:name=".MyService"/>
</application>

二、Service的兩種開(kāi)啟方式

1.startService() 啟動(dòng)服務(wù)。
開(kāi)啟服務(wù)后,服務(wù)就會(huì)長(zhǎng)期的后臺(tái)運(yùn)行,即使調(diào)用者退出了,服務(wù)仍然在后臺(tái)繼續(xù)運(yùn)行,服務(wù)和調(diào)用者沒(méi)有什么關(guān)系,調(diào)用者是不可以訪問(wèn)服務(wù)里面的方法。
2.bindService() 綁定服務(wù)。
服務(wù)開(kāi)啟后,生命周期與調(diào)用者相關(guān)聯(lián),調(diào)用者掛了,服務(wù)也會(huì)跟著掛掉,調(diào)用者和服務(wù)綁定在一起,調(diào)用者可以間接的調(diào)用到服務(wù)里面的方法。

三、Service的生命周期

接下來(lái)分別從兩種開(kāi)啟方式生命周期說(shuō)起,官方為我們提供了Service生命周期示意圖:


Service兩種形式的生命周期示意圖

1.startService() 啟動(dòng)服務(wù)
下面我們通過(guò)代碼來(lái)分析需要重寫(xiě)的回調(diào)方法有哪些?

public class MyService extends Service{

    // 綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("TAG","-MyService---onBind()----");
        return null;
    }
    //首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序,如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。該方法只被調(diào)用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("MyService","-MyService---onCreate()----");
    }
   //每次通過(guò)startService()方法啟動(dòng)Service時(shí)都會(huì)被回調(diào)。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("MyService","-MyService---onStartCommand()---intent:"
                + intent.getStringExtra("data"+"--flags="+flags+"-----startId"+startId));  
      return super.onStartCommand(intent, flags, startId);
    }
   //服務(wù)銷(xiāo)毀時(shí)的回調(diào)
    @Override
    public void onDestroy() {
        Log.e("MyService","-MyService---onDestroy()----");
        super.onDestroy();
    }
}

我們可以將Service看出一個(gè)沒(méi)有前臺(tái)界面的Activity,看看如何啟動(dòng)一個(gè)Service服務(wù)。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("TAG", "---MainActivity--onCreate-----");

        //啟動(dòng)服務(wù)
        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                intent.putExtra("data", "測(cè)試傳遞數(shù)據(jù)");
                //我們啟動(dòng)一個(gè)Activity的時(shí)候是startActivity();
                //在這里我們是啟動(dòng)一個(gè)service
                startService(intent);
            }
        });
        //停止服務(wù)
        findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, MyService.class);
                stopService(intent);
            }
        });
    }
    //生命周期方法
    ........
}

接下來(lái),我們看下運(yùn)行結(jié)果

TAG: ---MainActivity--onCreate-----
TAG: ---MainActivity--onStart-----
TAG: ---MainActivity--onResume-----
TAG: -MyService---onCreate()----
TAG: -MyService---onStartCommand()---intent=測(cè)試傳遞數(shù)據(jù)---flags=0-----startId=1
TAG: -MyService---onStartCommand()---intent=測(cè)試傳遞數(shù)據(jù)---flags=0-----startId=2
銷(xiāo)毀MainActivity
TAG: ---MainActivity--onPause-----
TAG: ---MainActivity--onStop-----
TAG: ---MainActivity--onDestroy-----
重新開(kāi)啟MainActivity
TAG: ---MainActivity--onCreate-----
TAG: ---MainActivity--onStart-----
TAG: ---MainActivity--onResume-----
銷(xiāo)毀service
TAG: -MyService---onDestroy()----

當(dāng)我們第一次啟動(dòng)服務(wù)時(shí)執(zhí)行onCreate()、onStartCommand方法,當(dāng)我們?cè)俅螁?dòng)服務(wù)的時(shí)候,是沒(méi)有執(zhí)行onCreate()方法的,只有當(dāng)Service沒(méi)有創(chuàng)建的時(shí)候才會(huì)回調(diào)這個(gè)方法,一旦Service被創(chuàng)建后再次startService啟動(dòng)Service也不會(huì)再次回調(diào)這個(gè)方法。當(dāng)MainActivity銷(xiāo)毀時(shí),我們發(fā)現(xiàn)MyService中并沒(méi)有執(zhí)行onDestroy(),只有當(dāng)我們?cè)俅螁?dòng)MainActivity,點(diǎn)擊了停止服務(wù)后,MyService服務(wù)才被銷(xiāo)毀了,即使調(diào)用者退出了,服務(wù)仍然在后臺(tái)繼續(xù)運(yùn)行。
關(guān)于這幾個(gè)方法的說(shuō)明如下:

  • onBind()
    當(dāng)另一個(gè)組件想通過(guò)調(diào)用 bindService() 與服務(wù)綁定時(shí),系統(tǒng)將調(diào)用此方法。在此方法的實(shí)現(xiàn)中,必須返回 一個(gè)IBinder 接口的實(shí)現(xiàn)類(lèi),供客戶端用來(lái)與服務(wù)進(jìn)行通信。無(wú)論是啟動(dòng)狀態(tài)還是綁定狀態(tài),此方法必須重寫(xiě),但在啟動(dòng)狀態(tài)的情況下直接返回 null。
  • onCreate()
    首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序(在調(diào)用 onStartCommand() 或onBind() 之前)。如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法,該方法只調(diào)用一次
  • onStartCommand(Intent intent, int flags, int startId)
    當(dāng)另一個(gè)組件(如 Activity)通過(guò)調(diào)用 startService() 請(qǐng)求啟動(dòng)服務(wù)時(shí),系統(tǒng)將調(diào)用此方法。一旦執(zhí)行此方法,服務(wù)即會(huì)啟動(dòng)并可在后臺(tái)無(wú)限期運(yùn)行。 如果自己實(shí)現(xiàn)此方法,則需要在服務(wù)工作完成后,通過(guò)調(diào)用 stopSelf() 或 stopService() 來(lái)停止服務(wù)。(在綁定狀態(tài)下,無(wú)需實(shí)現(xiàn)此方法。)
    我們看下這三個(gè)參數(shù):
  1. intent :?jiǎn)?dòng)時(shí),啟動(dòng)組件傳遞過(guò)來(lái)的Intent,如Activity可利用Intent封裝所需要的參數(shù)并傳遞給Service
  2. flags:表示啟動(dòng)請(qǐng)求時(shí)是否有額外數(shù)據(jù)
    可選值有0,START_FLAG_REDELIVERY,START_FLAG_RETRY
    0 代表沒(méi)有;
    START_FLAG_REDELIVERY 這個(gè)值代表了onStartCommand方法的返回值為
    START_REDELIVER_INTENT,而且在上一次服務(wù)被殺死前會(huì)去調(diào)用stopSelf方法停止服務(wù)。其中START_REDELIVER_INTENT意味著當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,則會(huì)重建服務(wù),并通過(guò)傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand(),此時(shí)Intent時(shí)有值的。
    START_FLAG_RETRY該flag代表當(dāng)onStartCommand調(diào)用后一直沒(méi)有返回值時(shí),會(huì)嘗試重新去調(diào)用onStartCommand()。
  3. startId:指明當(dāng)前服務(wù)的唯一ID,與stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根據(jù)ID停止服務(wù)。
    實(shí)際上onStartCommand的返回值int類(lèi)型才是最最值得注意的,它有三種可選值, START_STICKY,START_NOT_STICKY,START_REDELIVER_INTENT,它們具體含義如下:
    START_STICKY: 當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,一段時(shí)間后內(nèi)存再次空閑時(shí),系統(tǒng)將會(huì)嘗試重新創(chuàng)建此Service,一旦創(chuàng)建成功后將回調(diào)onStartCommand方法,但其中的Intent將是null,除非有掛起的Intent,如pendingintent,這個(gè)狀態(tài)下比較適用于不執(zhí)行命令、但無(wú)限期運(yùn)行并等待作業(yè)的媒體播放器或類(lèi)似服務(wù)。
    START_NOT_STICKY: 當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,即使系統(tǒng)內(nèi)存再次空閑時(shí),系統(tǒng)也不會(huì)嘗試重新創(chuàng)建此Service。除非程序中再次調(diào)用startService啟動(dòng)此Service,這是最安全的選項(xiàng),可以避免在不必要時(shí)以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時(shí)運(yùn)行服務(wù)。
    START_REDELIVER_INTENT:當(dāng)Service因內(nèi)存不足而被系統(tǒng)kill后,則會(huì)重建服務(wù),并通過(guò)傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand(),任何掛起 Intent均依次傳遞。與START_STICKY不同的是,其中的傳遞的Intent將是非空,是最后一次調(diào)用startService中的intent。這個(gè)值適用于主動(dòng)執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。
  • onDestroy()
    當(dāng)服務(wù)不再使用且將被銷(xiāo)毀時(shí),系統(tǒng)將調(diào)用此方法。服務(wù)應(yīng)該實(shí)現(xiàn)此方法來(lái)清理所有資源,如線程、注冊(cè)的偵聽(tīng)器、接收器等,這是服務(wù)接收的最后一個(gè)調(diào)用。

由于每次啟動(dòng)服務(wù)(調(diào)用startService)時(shí),onStartCommand方法都會(huì)被調(diào)用,因此我們可以通過(guò)該方法使用Intent給Service傳遞所需要的參數(shù),然后在onStartCommand方法中處理的事件,最后根據(jù)需求選擇不同的Flag返回值,以達(dá)到對(duì)程序更友好的控制。

2.bindService() 綁定服務(wù)

前面了解了啟動(dòng)和停止服務(wù)的方法,雖然服務(wù)是在活動(dòng)(Activity)里啟動(dòng)的,但在啟動(dòng)了服務(wù)后,活動(dòng)與服務(wù)基本上就沒(méi)有什么關(guān)系了。我們調(diào)用了startService()方法來(lái)啟東MyService這個(gè)服務(wù),然后MyService的OnCreate()和onStartCommand()方法就會(huì)得到執(zhí)行,之后服務(wù)會(huì)一直處于運(yùn)行狀態(tài),但是具體運(yùn)行的是什么邏輯,活動(dòng)就控制不了了。那么我們?cè)撊绾卧诨顒?dòng)中去控制Service呢,這就需要借助onBind()方法了。
比如,我們希望在MyService里提供一個(gè)下載功能,然后在活動(dòng)中可以決定何時(shí)開(kāi)始下載,以及查看下載進(jìn)度,創(chuàng)建一個(gè)專(zhuān)門(mén)的Binder對(duì)象來(lái)對(duì)下載功能進(jìn)行模擬:

public class MyService extends Service {

    private DownloadBinder mBinder = new DownloadBinder();

    // 綁定服務(wù)時(shí)才會(huì)調(diào)用,必須要實(shí)現(xiàn)的方法
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("TAG", "-MyService---onBind()----");
        return mBinder;
    }

    //首次創(chuàng)建服務(wù)時(shí),系統(tǒng)將調(diào)用此方法來(lái)執(zhí)行一次性設(shè)置程序,如果服務(wù)已在運(yùn)行,則不會(huì)調(diào)用此方法。該方法只被調(diào)用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG", "-MyService---onCreate()----");
    }
    
    //每次通過(guò)startService()方法啟動(dòng)Service時(shí)都會(huì)被回調(diào)。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("TAG", "-MyService---onStartCommand()---intent=" + intent.getStringExtra("data") + "---flags=" + flags + "-----startId=" + startId);
        return super.onStartCommand(intent, flags, startId);
    }

    //服務(wù)銷(xiāo)毀時(shí)的回調(diào)
    @Override
    public void onDestroy() {
        Log.e("TAG", "-MyService---onDestroy()----");
        super.onDestroy();
    }


    class DownloadBinder extends Binder {
        public void startDownload() {
            Log.e("TAG", "開(kāi)始下載......");
        }

        public int getProgress() {
            Log.e("TAG", "下載進(jìn)度......");
            return 0;
        }
    }
}

在這里,我們創(chuàng)建一個(gè)DownloadBinder類(lèi),并繼承自Binder,然后在其內(nèi)部模擬開(kāi)始下和查看下載進(jìn)度的方法,分別打印下日志信息。在MyService中創(chuàng)建DownloadBinder 的實(shí)例,然后在onBind()方法中返回這個(gè)實(shí)例,這樣MyService中的工作就全部完成了。
接下來(lái)我們?cè)贛ainActivity中調(diào)用這個(gè)方法

public class MainActivity extends AppCompatActivity {
    private MyService.DownloadBinder downloadBinder;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        /**
         * 系統(tǒng)會(huì)調(diào)用該方法以傳遞服務(wù)的 onBind() 方法返回的 IBinder。
         * 其中service便是服務(wù)端返回的IBinder實(shí)現(xiàn)類(lèi)對(duì)象,
         * 通過(guò)該對(duì)象我們便可以調(diào)用獲取LocalService實(shí)例對(duì)象,
         * 進(jìn)而調(diào)用服務(wù)端的公共方法。
         * 而ComponentName是一個(gè)封裝了組件(Activity, Service, BroadcastReceiver, or ContentProvider)信息的類(lèi),
         * 如包名,組件描述等信息,較少使用該參數(shù)。
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
        /**
         * Android 系統(tǒng)會(huì)在與服務(wù)的連接意外中斷時(shí)(例如當(dāng)服務(wù)崩潰或被終止時(shí))調(diào)用該方法。
         * 注意:當(dāng)客戶端取消綁定時(shí),系統(tǒng)“絕對(duì)不會(huì)”調(diào)用該方法。
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e("TAG", "---MainActivity--onCreate-----");

        //綁定服務(wù)
        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                bindService(intent, serviceConnection, BIND_AUTO_CREATE);
            }
        });
        //解綁服務(wù)
        findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(serviceConnection);
            }
        });
    }
}

我們看下運(yùn)行結(jié)果

TAG: -MyService---onCreate()----
-MyService---onBind()----
TAG: 開(kāi)始下載......
下載進(jìn)度......
TAG: -MyService---onDestroy()----

首先創(chuàng)建了一個(gè)ServiceConnection 的匿名類(lèi),在里面重寫(xiě)了onServiceConnected()方法和onServiceDisconnected()方法,這兩個(gè)方法分別會(huì)在活動(dòng)與服務(wù)成功綁定以及解除綁定的時(shí)候調(diào)用。在onServiceConnected()方法中,通過(guò)向下轉(zhuǎn)型得到了DownloadBinder實(shí)例,有了這個(gè)實(shí)例,我們就可以進(jìn)行操作服務(wù)了。
在這里我們可以看到也是需要Intent對(duì)象來(lái)實(shí)現(xiàn)的,和啟動(dòng)服務(wù)不一樣的是:啟動(dòng)服務(wù)時(shí) startService(),而綁定服務(wù)的時(shí)候是bindService(),bindService()方法接收3個(gè)參數(shù),第一個(gè)參數(shù)就是Intent對(duì)象,第二個(gè)參數(shù)就是ServiceConnection 的實(shí)例,第三個(gè)參數(shù)BIND_AUTO_CREATE 表示活動(dòng)和服務(wù)進(jìn)行綁定后自動(dòng)創(chuàng)建服務(wù)。這會(huì)使得MyService中的OnCreate()方法得到執(zhí)行,但是不會(huì)執(zhí)行onStartCommand()方法。
我們想要解除活動(dòng)和服務(wù)之間的綁定,就需要調(diào)用unbindService()方法,傳入當(dāng)前的ServiceConnection實(shí)例即可。
需要注意的是,任何一個(gè)服務(wù)在整個(gè)應(yīng)用程序范圍內(nèi)都是通用多的,MyService 可以和任何一個(gè)活動(dòng)進(jìn)行綁定,綁定完成后它們都可以獲取相同的DownloadBinder實(shí)例。

四、關(guān)于綁定服務(wù)的注意點(diǎn)

1.多個(gè)客戶端可同時(shí)連接到一個(gè)服務(wù)。不過(guò),只有在第一個(gè)客戶端綁定時(shí),系統(tǒng)才會(huì)調(diào)用服務(wù)的 onBind() 方法來(lái)檢索 IBinder。系統(tǒng)隨后無(wú)需再次調(diào)用 onBind(),便可將同一 IBinder 傳遞至任何其他綁定的客戶端。當(dāng)最后一個(gè)客戶端取消與服務(wù)的綁定時(shí),系統(tǒng)會(huì)將服務(wù)銷(xiāo)毀(除非 startService() 也啟動(dòng)了該服務(wù))。
2.通常情況下我們應(yīng)該在客戶端生命周期(如Activity的生命周期)的引入 和退出時(shí)刻設(shè)置綁定和取消綁定操作,以便控制綁定狀態(tài)下的Service,一般有以下兩種情況:
(1)如果只需要在 Activity 可見(jiàn)時(shí)與服務(wù)交互,則應(yīng)在 onStart() 期間綁定,在 onStop() 期間取消綁定。
(2)如果希望 Activity 在后臺(tái)停止運(yùn)行狀態(tài)下仍可接收響應(yīng),則可在 onCreate() 期間綁定,在 onDestroy() 期間取消綁定。需要注意的是,這意味著 Activity 在其整個(gè)運(yùn)行過(guò)程中(甚至包括后臺(tái)運(yùn)行期間)都需要使用服務(wù),因此如果服務(wù)位于其他進(jìn)程內(nèi),那么當(dāng)提高該進(jìn)程的權(quán)重時(shí),系統(tǒng)很可能會(huì)終止該進(jìn)程。
3.通常情況下(注意),切勿在 Activity 的 onResume() 和 onPause() 期間綁定和取消綁定,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào),這樣反復(fù)綁定與解綁是不合理的。此外,如果應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù),并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間),系統(tǒng)可能會(huì)銷(xiāo)毀服務(wù)并重建服務(wù),因此服務(wù)的綁定不應(yīng)該發(fā)生在 Activity 的 onResume() 和 onPause()中。
4.我們應(yīng)該始終捕獲 DeadObjectException DeadObjectException 異常,該異常是在連接中斷時(shí)引發(fā)的,表示調(diào)用的對(duì)象已死亡,也就是Service對(duì)象已銷(xiāo)毀,這是遠(yuǎn)程方法引發(fā)的唯一異常,DeadObjectException繼承自RemoteException,因此我們也可以捕獲RemoteException異常。
5.應(yīng)用組件(客戶端)可通過(guò)調(diào)用 bindService() 綁定到服務(wù),Android 系統(tǒng)隨后調(diào)用服務(wù)的 onBind() 方法,該方法返回用于與服務(wù)交互的 IBinder,而該綁定是異步執(zhí)行的。

IntentService

一、IntentService與Service的區(qū)別

IntentService是繼承并處理異步請(qǐng)求的一個(gè)類(lèi),在IntentService內(nèi)有一個(gè)工作線程來(lái)處理耗時(shí)操作,啟動(dòng)IntentService的方式和啟動(dòng)傳統(tǒng)的Service一樣,同時(shí),當(dāng)任務(wù)執(zhí)行完后,IntentService會(huì)自動(dòng)停止,而不需要我們手動(dòng)去控制或stopSelf()。另外,可以啟動(dòng)IntentService多次,而每一個(gè)耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且,每次只會(huì)執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)再執(zhí)行第二個(gè),以此類(lèi)推。

IntentService的源碼

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null.
     * @see android.app.Service#onBind
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     *               This may be null if the service is being restarted after
     *               its process has gone away; see
     *               {@link android.app.Service#onStartCommand}
     *               for details.
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

IntentService繼承自Service,內(nèi)部有一個(gè)HandlerThread對(duì)象。
????在onCreate的時(shí)候會(huì)創(chuàng)建一個(gè)HandlerThread對(duì)象,并啟動(dòng)線程。緊接著創(chuàng)建ServiceHandler對(duì)象,ServiceHandler繼承自Handler,用來(lái)處理消息。ServiceHandler將獲取HandlerThread的Looper就可以開(kāi)始正常工作了。
????每啟動(dòng)一次onStart方法,就會(huì)把數(shù)消息和數(shù)據(jù)發(fā)給mServiceHandler,相當(dāng)于發(fā)送了一次Message消息給HandlerThread的消息隊(duì)列。mServiceHandler會(huì)把數(shù)據(jù)傳個(gè)onHandleIntent方法,onHandleIntent是個(gè)抽象方法,需要在IntentService實(shí)現(xiàn),所以每次onStart方法之后都會(huì)調(diào)用我們自己寫(xiě)的onHandleIntent方法去處理。處理完畢使用stopSelf通知HandlerThread已經(jīng)處理完畢,HandlerThread繼續(xù)觀察消息隊(duì)列,如果還有未執(zhí)行玩的message則繼續(xù)執(zhí)行,否則結(jié)束。

IntentService的實(shí)現(xiàn):

public class MyIntentService extends IntentService{

    /**
     * 無(wú)參構(gòu)造方法 一定要實(shí)現(xiàn)此方法否則Service運(yùn)行出錯(cuò)。
     *
     * 錯(cuò)誤如下java.lang.RuntimeException: Unable to instantiate service com.monkey.servicedemo.MyIntentService:
     * java.lang.InstantiationException: java.lang.Class<com.monkey.servicedemo.MyIntentService> has no zero argument constructor
     */
    public MyIntentService() {
        super("MyIntentService");
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.e("MyIntentService--", "onHandleIntent()");
        //耗時(shí)操作
        for(int i = 0; i < 3; i++){
            Log.e("onHandleIntent--",  i + "--" + Thread.currentThread().getName());
        }

    }

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

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.e("MyIntentService--", "onStartCommand()");
        return super.onStartCommand(intent, flags, startId);

    }

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

啟動(dòng)IntentService

  //啟動(dòng)前一定不要忘記注冊(cè)
   <service android:name=".MyIntentService"/>

  Intent intent = new Intent(MainActivity.this, MyIntentService.class);
  startService(intent);

運(yùn)行結(jié)果

E/MyIntentService--: onCreate()
E/MyIntentService--: onStartCommand()
E/MyIntentService--: onHandleIntent()
E/onHandleIntent--: 0--IntentService[MyIntentService]
1--IntentService[MyIntentService]
2--IntentService[MyIntentService]
E/MyIntentService--: onDestroy()

IntentService開(kāi)啟后,執(zhí)行完onHandleIntent里面的任務(wù)就自動(dòng)銷(xiāo)毀結(jié)束,并不需要我們?nèi)ブ鲃?dòng)的關(guān)閉。
總結(jié):
1、啟動(dòng) IntentService 是不需要新建線程。IntentService內(nèi)部的HandlerThread 繼承自 Thread,內(nèi)部封裝了 Looper,在這里新建線程并啟動(dòng),所以啟動(dòng) IntentService 不需要新建線程。
2、不建議通過(guò) bindService() 啟動(dòng) IntentService。IntentService 源碼中的 onBind() 默認(rèn)返回 null;不適合 bindService() 啟動(dòng)服務(wù),如果你執(zhí)意要 bindService() 來(lái)啟動(dòng) IntentService,可能因?yàn)槟阆胪ㄟ^(guò) Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,這樣那么 onHandleIntent() 不會(huì)被回調(diào),相當(dāng)于在你使用 Service 而不是 IntentService。
3、多次啟動(dòng) IntentService 會(huì)順序執(zhí)行事件,停止服務(wù)后,后續(xù)的事件得不到執(zhí)行。IntentService 中使用的 Handler、Looper、MessageQueue 機(jī)制把消息發(fā)送到線程中去執(zhí)行的,所以多次啟動(dòng) IntentService 不會(huì)重新創(chuàng)建新的服務(wù)和新的線程,只是把消息加入消息隊(duì)列中等待執(zhí)行,而如果服務(wù)停止,會(huì)清除消息隊(duì)列中的消息,后續(xù)的事件得不到執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

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

  • 服務(wù)基本上分為兩種形式 啟動(dòng) 當(dāng)應(yīng)用組件(如 Activity)通過(guò)調(diào)用 startService() 啟動(dòng)服務(wù)時(shí)...
    pifoo閱讀 1,279評(píng)論 0 8
  • Service的生命周期 service的生命周期,從它被創(chuàng)建開(kāi)始,到它被銷(xiāo)毀為止,可以有兩條不同的路徑: A s...
    _執(zhí)_念__閱讀 1,573評(píng)論 0 19
  • 什么是Service Service是一個(gè)應(yīng)用組件, 它用來(lái)在后臺(tái)完成一個(gè)時(shí)間跨度比較大的工作且沒(méi)有關(guān)聯(lián)任何界面 ...
    Mr丶sorrow閱讀 695評(píng)論 0 1
  • Service的相關(guān)知識(shí)雖然簡(jiǎn)單,但是也比較瑣碎,其衍生知識(shí)也比較多。本篇從Service的生命周期、運(yùn)行和使用方...
    卑鄙的鹿尤菌閱讀 822評(píng)論 0 1
  • 快要將一本書(shū)學(xué)完了,非常開(kāi)心!也很開(kāi)心能在簡(jiǎn)書(shū)上認(rèn)識(shí)很多志同道合的朋友,前幾日被簡(jiǎn)書(shū)好友宛風(fēng)的禪繞畫(huà)所吸引,打算今...
    風(fēng)吹海樹(shù)閱讀 465評(píng)論 7 10