Android Service和IntentService知識點詳細總結(jié)

Service 對于廣大的Android開發(fā)者來說算是耳熟能詳了,作為Android的四大組件之一,在我們的開發(fā)中也起著重要的作用,在Android面試中,Service相關(guān)的問題也是面試官問得比較多的,當別人問你,Service 到底是什么的時候?你可能隨口就能答得上來,Service是一個在后臺執(zhí)行長時間運行操作而不用提供用戶界面的應(yīng)用組件,可由其他組件啟動,即使用戶切換到其他應(yīng)用程序,Service 仍然在后臺繼續(xù)運行。沒錯,這是Service的概念,作為Android開發(fā),或多或少都知道一些,但是不是每個人把所有知識點都了解得透測。前段時間由于項目中有用到Service,因此,本篇文章對Service的用法做一個總結(jié)。

Service 目錄.png

Service

Service 和Activity 一樣同為Android 的四大組件之一,并且他們都有各自的生命周期,要想掌握Service 的用法,那就要了解Service 的生命周期有哪些方法,并且生命周期中各個方法回調(diào)的時機和作用。有一點比較重要,Service 有兩種啟動方式,并且它的兩種啟動方式的生命周期是不一樣的。接下來來分別看一下兩種啟動方式各自的生命周期方法。

startService方式啟動Service

當應(yīng)用組件通過startService方法來啟動Service 時,Service 則會處于啟動狀態(tài),一旦服務(wù)啟動,它就會在后臺無限期的運行,生命周期獨立于啟動它的組件,即使啟動它的組件已經(jīng)銷毀了也不受任何影響,由于啟動的服務(wù)長期運行在后臺,這會大量消耗手機的電量,因此,我們應(yīng)該在任務(wù)執(zhí)行完成之后調(diào)用stopSelf()來停止服務(wù),或者通過其他應(yīng)用組件調(diào)用stopService 來停止服務(wù)。

startService 啟動服務(wù)后,會執(zhí)行如下生命周期:onCreate() ->onStartCommand() -> onStart()(現(xiàn)在已經(jīng)廢棄) -> onDestroy() 。具體看一下它的幾個生命周期方法:

  • onCreate() :首次啟動服務(wù)的時候,系統(tǒng)會調(diào)用這個方法,在onStartCommand 和 onBind 方法之前,如果服務(wù)已經(jīng)啟動起來了,再次啟動時,則不會調(diào)用此方法,因此可以在onCreate 方法中做一些初始化的操作,比如要執(zhí)行耗時的操作,可以在這里創(chuàng)建線程,要播放音樂,可以在這里初始化音樂播放器。

  • onStartCommand(): 當通過startService 方法來啟動服務(wù)的時候,在onCreate 方法之后就會回調(diào)這個方法,此方法調(diào)用后,服務(wù)就啟動起來了,將會在后臺無限期的運行,直到通過stopService 或者 stopSelf 方法來停止服務(wù)。

  • onDestroy():當服務(wù)不再使用且將被銷毀時,系統(tǒng)將調(diào)用此方法。服務(wù)應(yīng)該實現(xiàn)此方法來清理所有資源,如線程、注冊的偵聽器、接收器等。 這是服務(wù)接收的最后一個調(diào)用。

了解了這幾個生命周期方法后,我們就來寫一個簡單Service 。

要使用Service 就要通過繼承Service類(或者繼承IntentService ,后文會講)來實現(xiàn),代碼如下:

public class SimpleService extends Service {
    public static final String TAG = "SimpleService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"call onBind...");
        return null;
    }

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

    @Override
    public void onStart(Intent intent, int startId) {
        Log.i(TAG,"call onStart...");
    }

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

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



}

Service類寫好了之后,我們需要在清單文件中注冊一下,在<application> 標簽下:

        <service android:name=".service.SimpleService"
                 android:exported="false"
            />

寫好了Service并且在清單文件注冊之后,我們就可以啟動Service了,啟動Service和啟動Activity 差不多,通過Intent 來啟動,代碼如下:

  @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_service:
                Intent intent = new Intent(this,SimpleService.class);
                // 啟動服務(wù)
                startService(intent);
                break;
            case R.id.stop_service:
                Intent service = new Intent(this,SimpleService.class);
                // 停止服務(wù)
                stopService(service);
                break;
        }
    }
界面.png

如上圖界面所示,有2 個button ,分別是啟動服務(wù)和停止服務(wù),分別點擊 startService 和StopService 的button ,看看生命周期回調(diào)方法打印的日志:


生命周期打印日志.png

小結(jié):通過startService 方式啟動的服務(wù),服務(wù)會無限期的在后臺運行,直到通過stopService 或 stopSelf 來終止服務(wù)。服務(wù)獨立于啟動它的組件,也就是說,當組件啟動服務(wù)后,組件和服務(wù)就再也沒有關(guān)系了,就算啟動它的組件被銷毀了,服務(wù)照樣在后臺運行。通過這種方式啟動的服務(wù)不好與組件之間通信。

bindService 方式啟動服務(wù)

除了startService 來啟動服務(wù)之外,另外一種啟動服務(wù)的方式就是通過bindService 方法了,也就是綁定服務(wù),其實通過它的名字就容易理解,綁定即將啟動組件和服務(wù)綁定在一起。前面講的通過startService 方式啟動的服務(wù)是與組件相獨立的,即使啟動服務(wù)的組件被銷毀了,服務(wù)仍然在后臺運行不受干擾。但是通過bindSerivce 方式綁定的服務(wù)就不一樣了,它與綁定組件的生命周期是有關(guān)的。如下:

多個組件可以綁定到同一個服務(wù)上,如果只有一個組件綁定服務(wù),當綁定的組件被銷毀時,服務(wù)也就會停止了。如果是多個組件綁定到一個服務(wù)上,當綁定到該服務(wù)的所有組件都被銷毀時,服務(wù)才會停止。

bindService 綁定服務(wù) 和startService 的生命周期是不一樣,bindServie 的生命周期如下:onCreate -> onBind -> onUnbind ->onDestroy。其中重要的就是onBind 和onUnbind 方法。

  • onBind(): 當其他組件想通過bindService 與服務(wù)綁定時,系統(tǒng)將會回調(diào)這個方法,在實現(xiàn)中,你必須返回一個IBinder接口,供客戶端與服務(wù)進行通信,必須實現(xiàn)此方法,這個方法是Service 的一個抽象方法,但是如果你不允許綁定的話,返回null 就可以了。

  • onUnbind(): 當所有與服務(wù)綁定的組件都解除綁定時,就會調(diào)用此方法。

了解了這2個方法后,我們來看一下怎么綁定一個服務(wù)。
1,首先,添加一個類 繼承 Binder ,在Binder 類中添加其他組件要與服務(wù)交互的方法,并在onBind() 方法中返回IBinder 實例對象:

public class SimpleService extends Service {
    public static final String TAG = "SimpleService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"call onBind...");
        //返回IBinder 接口對象
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG,"call onUnbind...");
        return super.onUnbind(intent);
    }

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

    @Override
    public void onStart(Intent intent, int startId) {
        Log.i(TAG,"call onStart...");
    }

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

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

    // 添加一個類繼承Binder
    public  class MyBinder extends Binder{
        // 添加要與外界交互的方法
        public String  getStringInfo(){
          return "調(diào)用了服務(wù)中的方法";
        }
    }

}

2, 綁定服務(wù)的時候,需要提供一個ServiceConnection 接口,在接口回調(diào)中獲取Binder 對象,與服務(wù)進行通信。

 private SimpleService.MyBinder mMyBinder;
    // 綁定/解除綁定 Service 回調(diào)接口
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 綁定成功后回調(diào)
            //1 ,獲取Binder接口對象
            mMyBinder = (SimpleService.MyBinder) service;
            //2, 從服務(wù)獲取數(shù)據(jù)
            String content = mMyBinder.getStringInfo();
            // 3,界面提示
            Toast.makeText(ServiceSimpleActivity.this,content,Toast.LENGTH_LONG).show();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
           // 解除綁定后回調(diào)
            mMyBinder = null;
        }
    };

3,綁定和解除綁定服務(wù)

            case R.id.bind_service:
                Intent intent = new Intent(this,SimpleService.class);
                // 綁定服務(wù)
                bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.unbind_service:
                // 解除綁定服務(wù)
                unbindService(mConnection);

                break;

點擊綁定按鈕,即綁定服務(wù),并且在onServiceConnected 中得到MyBinder 對象,就可以通過這個對象和服務(wù)通信了,例子中我們Toast 了從服務(wù)中獲取的字符串:

綁定服務(wù).png

生命周期方法調(diào)用如下:


image.png

可以看到,綁定服務(wù)的生命周期內(nèi)依次調(diào)用了onCreate ,onBind,onUnbind 和 onDestroy 方法,只有中間兩個生命周期方法與startService 啟動服務(wù)是不同的。一張圖就能看清兩種方式的生命周期的異同:

Service生命周期.png

tips: Service 的生命周期方法不同于Activity ,不需要調(diào)用超類的生命周期方法,如:不用調(diào)用 super.onCreate()

多個組件綁定同一服務(wù)

Service 是支持多個組件綁定在同一個服務(wù)上的,第一個組件綁定是會回調(diào) onCreate 生命周期方法,后續(xù)的綁定只會調(diào)用onBind方法,返回IBinder給客戶端。當綁定在服務(wù)上的組件都調(diào)用unbindService 解除綁定服務(wù)或者組件本身就已經(jīng)被系統(tǒng)回收,那么服務(wù)也就會被停止回收了,會回調(diào)onUnbind 和 onDestroy 方法。

Service 與應(yīng)用組件通信的幾種方式

1,BroadcastReceiver
通過前文我們知道,startService方式啟動的服務(wù)在后臺,無限期地運行,并且與啟動它的組件是獨立的,啟動Service 之后也就與啟動它的組件沒有任何關(guān)系了。因此它是不能與啟動它的組件之間相互通信的。雖然Service 沒有提供這種啟動方式的通信方法,我們還是可以通過其他方式來解決的,這就用到了BroadcastReceiver。

場景描述:通過startService 啟動一個長期在后臺運行的下載圖片服務(wù),然后在界面上點擊下載按鈕,通過intent 傳遞一個下載鏈接給Service,在下載完成后,通過BroadcastReceiver 通知Activity 界面顯示圖片。看一下代碼實現(xiàn):

Service代碼如下:

public class DownloadService extends Service {
    public static final String IMAGE = "iamge_url";
    public static final String RECEIVER_ACTION = "com.zhouwei.simpleservice";
    private static final String TAG = "DownloadService";
    public static final String ACTION_START_SERVICER = "com.zhouwei.startservice";
    public static final String ACTION_DOWNLOAD = "com.zhouwei.startdownload";
    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            // 工作線程做耗時下載
            String url = (String) msg.obj;
            Bitmap bitmap = null;
            try {
                bitmap = Picasso.with(getApplicationContext()).load(url).get();
                Intent intent = new Intent();
                intent.putExtra("bitmap",bitmap);
                intent.setAction(RECEIVER_ACTION);
                // 通知顯示
                LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
            } catch (IOException e) {
                e.printStackTrace();
            }


            //工作完成之后,停止服務(wù)
            stopSelf();
        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        // 開啟一個工作線程做耗時工作
        HandlerThread thread = new HandlerThread("ServiceHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
        // 獲取工作線程的Looper
        mServiceLooper = thread.getLooper();
        // 創(chuàng)建工作線程的Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG,"call onStartCommand...");
        if(intent.getAction().equals(ACTION_DOWNLOAD)){
            handleCommand(intent);
        }else if(intent.getAction().equals(ACTION_START_SERVICER)){
            //do nothing
        }

        return START_STICKY;
    }

    private void handleCommand(Intent intent){
        String url = intent.getStringExtra(IMAGE);
        // 發(fā)送消息下載
        Message message = mServiceHandler.obtainMessage();
        message.obj = url;
        mServiceHandler.sendMessage(message);
    }
}

新建了一個DownloadService ,在里面啟動了一個工作線程,在線程里下載圖片,然后通過BroadcastReceiver 通知Activity顯示。

Activity的代碼很簡單,注冊BroadcastReceiver,在onReceiver中顯示圖片就好了,代碼如下:

private ImageView mImageView;
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 顯示圖片
            Bitmap bitmap = intent.getParcelableExtra("bitmap");
            mImageView.setImageBitmap(bitmap);
        }
    };


    /**
     * 啟動下載
     */
    private void startDownload(){
        Intent intent = new Intent(this,DownloadService.class);
        // 啟動服務(wù)
        intent.putExtra(DownloadService.IMAGE,"http://www.8kmm.com/UploadFiles/2012/8/201208140920132659.jpg");
        intent.setAction(DownloadService.ACTION_DOWNLOAD);
        startService(intent);
    }

效果如下:

Service下載圖片.gif

如上就完成了使用BroadcastReceiver 完成和組件和Service的通信。

2, LocaService 使用Binder 和 服務(wù)通信
既然通過startService 啟動的服務(wù)與啟動它的組件是獨立的。相互通信比較麻煩,那么Google也提供了兩者之間的通信方法,那就是組件綁定服務(wù),也就是上文講的通過bindService 將組件和服務(wù)綁定到一起。組件可以獲取Service 通過onBind返回的一個IBinder接口,這樣兩者就可以通信了,這也是Service 應(yīng)用類通信比較常用的方式。

下面就模擬一個用服務(wù)播放音樂的例子來講一下組件通過Binder 接口和服務(wù)之間通信。
首先定義一個通信的接口 IPlayer:

/**
 * Created by zhouwei on 17/5/11.
 */

public interface IPlayer {
    // 播放
    public void play();
    // 暫停
    public void pause();
    // 停止
    public void stop();
    // 獲取播放進度
    public int getProgress();
    // 獲取時長
    public int getDuration();
}

然后添加一個MusicService 類,繼承Service 實現(xiàn) Iplayer 接口:

public class MusicService extends Service implements IPlayer{
    public static final String TAG = "MusicService";
    private LocalService mBinder = new LocalService();
    public class LocalService extends Binder{
        public MusicService getService(){
            return MusicService.this;
        }
    }

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

    @Override
    public void play() {
        Log.i(TAG,"music play...");
    }

    @Override
    public void pause() {
        Log.i(TAG,"music pause...");
    }

    @Override
    public void stop() {
        Log.i(TAG,"music stop...");
    }

    @Override
    public int getProgress() {
        return 100;
    }

    @Override
    public int getDuration() {
        return 10240;
    }
}

其中比較重要的就是內(nèi)部類LocalService ,繼承Binder ,里面提供一個getService 方法,返回MusicService 實例,組件通過IBinder 獲取到Music 實例后,就可以和Service之間相互通信啦!

Activity中代碼如下:

 private MusicService.LocalService mLocalService;
    private MusicService mMusicService;
    // 綁定/解除綁定 Service 回調(diào)接口
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //1 ,獲取Binder接口對象
            mLocalService = (MusicService.LocalService) service;
            //2, 獲取MusicService 實例
            mMusicService = mLocalService.getService();

            // 只要拿到Music Service 實例之后,就可以調(diào)用接口方法了
            // 可以通過它來播放/暫停音樂,還可以通過它來獲取當前播放音樂的進度,時長等等

            mMusicService.play();

            mMusicService.pause();

            mMusicService.stop();

            int progress = mMusicService.getProgress();
            Log.i(MusicService.TAG,"progress:"+progress);

            int duration = mMusicService.getDuration();
            Log.i(MusicService.TAG,"duration:"+duration);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
           // 解除綁定后回調(diào)
            mMusicService = null;
            mLocalService = null;
        }
    };

獲取到MusicService 后,就可以調(diào)用接口方法了,比如:播放音樂,暫停、停止、獲取進度等等。
看一下打印的日志:

模擬播放音樂.png

** 使用AIDL 通信 (跨進城通信IPC)**
AIDL(Android 接口定義語言)執(zhí)行所有將對象分解成原語的工作,操作系統(tǒng)可以識別這些原語并將它們編組到各進程中,以執(zhí)行 IPC。 如果不是多線程訪問服務(wù)的話,也可以使用Messenger來跨進城通信,Messenger
方法實際上是以 AIDL 作為其底層結(jié)構(gòu)。Messenger
會在單一線程中創(chuàng)建包含所有客戶端請求的隊列,以便服務(wù)一次接收一個請求。 不過,如果您想讓服務(wù)同時處理多個請求,則可直接使用 AIDL。 在此情況下,您的服務(wù)必須具備多線程處理能力,并采用線程安全式設(shè)計。如需直接使用 AIDL,您必須創(chuàng)建一個定義編程接口的 .aidl
文件。Android SDK 工具利用該文件生成一個實現(xiàn)接口并處理 IPC 的抽象類,您隨后可在服務(wù)內(nèi)對其進行擴展。

由于篇幅有限,AIDL 實現(xiàn)進程間的通信后面單獨出一篇文章講,這里就不再啰嗦了。

注意:只有允許不同的客戶端用IPC 方式訪問服務(wù),并且想要在服務(wù)中處理多線程時,采用AIDL,如果不想通過IPC實現(xiàn)不同應(yīng)用的訪問,直接用前面所講的繼承Binder ,用接口通信就可以了。

Service 總結(jié)

Service 有2種啟動方式,startService 啟動服務(wù),服務(wù)啟動起來后,在后臺無限期運行,直到通過stopService 或者 stopSelf 停止服務(wù),服務(wù)與組件獨立,通信比較困難(但還是有辦法的,通過BroadcastReceiver )。另一種方式就是 bindService 即綁定服務(wù),組件和服務(wù)綁定在一起,服務(wù)的生命后期受組件影響,如果綁定到服務(wù)的組件全部被銷毀了,那么服務(wù)也就會停止了。綁定服務(wù)的方式通常用于組件和服務(wù)之間 需要相互通信。startService 這種 方式一般用于在后臺執(zhí)行任務(wù),而不需要返回結(jié)果給組件。 這兩種方式并非完全獨立,也就是說,你可以綁定已經(jīng)通過 startService 啟動起來的服務(wù),可以通過在Intent 中添加Action 來標示要執(zhí)行的動作。比如:通過Intent Action 標記要播放的音樂,調(diào)用startService 來啟動音樂服務(wù)播放音樂,在界面需要顯示播放進度的時候,可以通過binderService 來綁定服務(wù),從而獲取歌曲信息。這種情況下,Service 需要實現(xiàn)兩種方式的生命周期。這種情況下,除非所有客戶端都已經(jīng)取消綁定,否則通過stopService 或者 stopSelf 是不能停止服務(wù)的。

Service 是運行在主線程中的,因此不能執(zhí)行耗時的或者密集型的任務(wù),如果要執(zhí)行耗時操作或者密集型計算任務(wù),請在服務(wù)中開啟工作線程,在線程中執(zhí)行。或者使用下面一節(jié)將要講的IntentService。

IntentService

IntentService 是Service 的子類,它使用工作線程逐一處理所有啟動請求,果您不要求服務(wù)同時處理多個請求,這是最好的選擇。 您只需實現(xiàn) onHandIntent方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執(zhí)行后臺工作。

IntentService 示例

IntentService 默認為我們開啟了一個工作線程,在任務(wù)執(zhí)行完畢后,自動停止服務(wù),因此在我們大多數(shù)的工作中,使用IntentService 就夠了,并且IntentService 比較簡單,只要實現(xiàn)一個方法OnHandleIntent,接下來看一下示例:

IntentService 擴展類:

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

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
      // 這里已經(jīng)是工作線程,在這里執(zhí)行操作就行

       boolean isMainThread =  Thread.currentThread() == Looper.getMainLooper().getThread();
        Log.i(TAG,"is main thread:"+isMainThread);

        // 執(zhí)行耗時下載操作
        mockDownload();
    }

    /**
     * 模擬執(zhí)行下載
     */
    private void mockDownload(){
       try {
           Thread.sleep(5000);
           Log.i(TAG,"下載完成...");
       }catch (Exception e){
           e.printStackTrace();
       }
    }
}

然后啟動服務(wù),看一下打印的日志,如下圖:

image.png

判斷了是否為主線程,結(jié)果為false ,說明是開啟了一個工作線程,5s 之后,打印了下載完成,并且自動停止了服務(wù)。

IntentService 源碼淺析

IntentService 自動為我們開啟了一個線程來執(zhí)行耗時操作,并且在任務(wù)完成后自動停止服務(wù),那么它是怎么做的呢?我們看一下源碼一探究竟。其實IntentService 的源碼非常簡單,就一百多行。一起看一下:

   // 1,有一個Looper 變量和一個ServiceHandler 變量,ServiceHander 繼承Handler 處理消息
    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) {
           // 在工作線程中調(diào)用onHandleIntent,子類根據(jù)Intent傳遞的數(shù)據(jù)執(zhí)行具體的操作
            onHandleIntent((Intent)msg.obj);
          // 任務(wù)執(zhí)行完畢后,自動停止Service
            stopSelf(msg.arg1);
        }
    }
//2, 在OnCreate 方法中,創(chuàng)建了一個線程HandlerThread ,并啟動線程
// 然后獲取工作線程的Looper ,并用Looper 初始化Handler(我們都知道Handler 的創(chuàng)建需要一依賴Looper)
 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);
    }
//3, 在onStart()方法中發(fā)送消息給Handler,并且把Intent 傳給了Handler 處理
 @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
// 4,onStartCommand 直接調(diào)用的是onStart方法
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
// 5 最后就是一個子類需要實現(xiàn)的抽象方法,這個方法在handleMessage中調(diào)用,也就是在工作線程中執(zhí)行。
 protected abstract void onHandleIntent(@Nullable Intent intent);

上面代碼中注釋得很清楚,下面用一張圖來看一下整個過程.

IntentService圖解.png

代碼很簡單,IntentService的源碼看著是不是很熟悉?當然很熟悉,前面使用Service的時候,在Service 里面開啟工作線程其實就和Intent Service的代碼差不多。在onCreate中創(chuàng)建線程,啟動,初始化Handler和Looper ,然后在onStartCommand中發(fā)送消息給Handler 處理任務(wù)。

IntentService 總結(jié)

IntentService是Service 的子類,默認給我們開啟了一個工作線程執(zhí)行耗時任務(wù),并且執(zhí)行完任務(wù)后自 動停止服務(wù)。擴展IntentService比較簡單,提供一個構(gòu)造方法和實現(xiàn)onHandleIntent 方法就可了,不用重寫父類的其他方法。但是如果要綁定服務(wù)的話,還是要重寫onBind 返回一個IBinder 的。使用Service 可以同時執(zhí)行多個請求,而使用IntentService 只能同時執(zhí)行一個請求。

以上就是對Service 和IntentService的詳細總結(jié),如果問題,歡迎討論。 所有Demo代碼已上傳Github:https://github.com/pinguo-zhouwei/AndroidTrainingSimples(包含我所有博客的所講的知識點的Demo代碼)

參考:
API Guides 服務(wù)
Android 接口定義語言 (AIDL)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 前言:本文所寫的是博主的個人見解,如有錯誤或者不恰當之處,歡迎私信博主,加以改正!原文鏈接,demo鏈接 Serv...
    PassersHowe閱讀 1,446評論 0 5
  • [文章內(nèi)容來自Developers] Service是一個可以在后臺執(zhí)行長時間運行操作而不提供用戶界面的應(yīng)用組件。...
    岳小川閱讀 888評論 0 7
  • 轉(zhuǎn)載注明出處:http://www.lxweimin.com/p/a1d3d9693e91 1. 簡介 與前一篇An...
    王三的貓阿德閱讀 1,980評論 1 9
  • 我所在的小城,四季不分明,有很熱很長的夏天,也有不太冷很短的冬天,只是沒有秋天。沒有秋風一緊,小城里的人看不到草木...
    惠風和暢806閱讀 393評論 2 2
  • 擺攤記4.18 上周末天氣不好,沒有去擺攤。 不過周日下午看天氣預(yù)報,明天(也就是今天)似乎沒有雨,于是當天晚上冒...
    小棕櫚閱讀 285評論 0 0