Android四大組件之Service

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

Service

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

一、創(chuàng)建Service

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

public class MyService extends Service{

    //綁定服務時才會調(diào)用,必須要實現(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標簽中-->
        <service android:name=".MyService"/>
</application>

二、Service的兩種開啟方式

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

三、Service的生命周期

接下來分別從兩種開啟方式生命周期說起,官方為我們提供了Service生命周期示意圖:


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

1.startService() 啟動服務
下面我們通過代碼來分析需要重寫的回調(diào)方法有哪些?

public class MyService extends Service{

    // 綁定服務時才會調(diào)用,必須要實現(xiàn)的方法
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("TAG","-MyService---onBind()----");
        return null;
    }
    //首次創(chuàng)建服務時,系統(tǒng)將調(diào)用此方法來執(zhí)行一次性設置程序,如果服務已在運行,則不會調(diào)用此方法。該方法只被調(diào)用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("MyService","-MyService---onCreate()----");
    }
   //每次通過startService()方法啟動Service時都會被回調(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);
    }
   //服務銷毀時的回調(diào)
    @Override
    public void onDestroy() {
        Log.e("MyService","-MyService---onDestroy()----");
        super.onDestroy();
    }
}

我們可以將Service看出一個沒有前臺界面的Activity,看看如何啟動一個Service服務。

public class MainActivity extends AppCompatActivity {

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

        //啟動服務
        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", "測試傳遞數(shù)據(jù)");
                //我們啟動一個Activity的時候是startActivity();
                //在這里我們是啟動一個service
                startService(intent);
            }
        });
        //停止服務
        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);
            }
        });
    }
    //生命周期方法
    ........
}

接下來,我們看下運行結(jié)果

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

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

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

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

2.bindService() 綁定服務

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

public class MyService extends Service {

    private DownloadBinder mBinder = new DownloadBinder();

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

    //首次創(chuàng)建服務時,系統(tǒng)將調(diào)用此方法來執(zhí)行一次性設置程序,如果服務已在運行,則不會調(diào)用此方法。該方法只被調(diào)用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG", "-MyService---onCreate()----");
    }
    
    //每次通過startService()方法啟動Service時都會被回調(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);
    }

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


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

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

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

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

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

        //綁定服務
        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);
            }
        });
        //解綁服務
        findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(serviceConnection);
            }
        });
    }
}

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

TAG: -MyService---onCreate()----
-MyService---onBind()----
TAG: 開始下載......
下載進度......
TAG: -MyService---onDestroy()----

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

四、關于綁定服務的注意點

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

IntentService

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

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

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

IntentService的實現(xiàn):

public class MyIntentService extends IntentService{

    /**
     * 無參構造方法 一定要實現(xiàn)此方法否則Service運行出錯。
     *
     * 錯誤如下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()");
        //耗時操作
        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();
    }
}

啟動IntentService

  //啟動前一定不要忘記注冊
   <service android:name=".MyIntentService"/>

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

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

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

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