Service的生命周期

原作者:[在一顆大大大榕樹下
原鏈接:[ http://www.itdecent.cn/p/902aa6a8f604 ]

概念:Android四大組件之一,沒有可視化界面,是一個(gè)運(yùn)行于后臺(tái)的服務(wù)程序。

目錄

  • Service和線程的區(qū)別和場景
  • 管理Service的生命周期
  • service和IntentService有什么區(qū)別
  • 啟動(dòng)服務(wù)綁定服務(wù)先后次序問題
  • 遠(yuǎn)程服務(wù)AIDL
  • Binder
  1. Service和線程的區(qū)別和場景

我們都知道,Service和線程呢,都是在后臺(tái)運(yùn)行的,那么google為什么要為android系統(tǒng)創(chuàng)造出Service這么一個(gè)組件呢?我們先來看下線程和Service的特點(diǎn)。

Thread

程序最小的執(zhí)行單元,他是分配給CPU的基本單位

生命周期

  1. 新建(new Thread)
  2. 就緒 (線程已經(jīng)啟動(dòng),等待CPU資源)
  3. 運(yùn)行(run已經(jīng)獲得資源)
  4. 死亡(執(zhí)行完成或被殺死)
  5. 阻塞(因?yàn)槟撤N原因線程讓出cpu資源,就會(huì)進(jìn)入阻塞狀態(tài))

這里可以看出來一個(gè)致命的問題

線程一但run了起來,就和Activity失去關(guān)聯(lián)了。
即使Activity被干掉了,Thread依舊能快樂的執(zhí)行下去。

Thread是無法控制的。
google:這問題很大。

image

OK,于是我們的Service就誕生了。

  1. 管理Service的生命周期

Service的生命周期

  • onCreate
  • onStart
  • onDestroy
  • onBind
  • onUnBind

我們來看一下,Activity是如何管理Service的,他的生命周期又是如何變化的。

  • 啟動(dòng)服務(wù):startService
23:42:02.003 1173-1173/? I/MyService: onCreate
23:42:02.003 1173-1173/? I/MyService: onStartCommand

注意,多次調(diào)用startService() 方法,onCreate只會(huì)調(diào)用一次,但是onStartCommand會(huì)調(diào)用多次

  • 停止服務(wù):stopService
23:45:17.443 1292-1292/com.yirong.androidpractice I/MyService: onDestroy

注意,在調(diào)用bindService之后,就算調(diào)用stopService也無法停止服務(wù),必須先解綁

  • 綁定服務(wù):bindService
   bindService(intent,this, Context.BIND_AUTO_CREATE)
   stopService(intent)

00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onCreate
00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onBind

劃重點(diǎn):bindService不調(diào)用onStart方法

  • 解綁服務(wù):unBindService
00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onUnbind
00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onDestroy

  1. service和IntentService有什么區(qū)別

首先得劃個(gè)重點(diǎn):Service是在主線程中運(yùn)行的,所以不能做耗時(shí)操作,會(huì)報(bào)ANR異常

image

不能做耗時(shí)操作,就意味著無法替代Thread的功能,那這Service啥意義啊?

這就是IntentServiceService區(qū)別了。

打開源碼,按照慣例看下腦袋這塊兒的小灰字。

總結(jié)下,大概就這么點(diǎn)意思:

  • IntentService是一個(gè)繼承并處理異步請求的類
  • 他的內(nèi)部有一個(gè)工作線程來處理耗時(shí)操作

扒一段源碼看看

@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);
    }

一看就明白了,底層還是Thread寫的,但是對(duì)Thread做了處理。
點(diǎn)開HandlerThread,直接看重點(diǎn):

public class HandlerThread extends Thread {
    ...
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//為當(dāng)前線程創(chuàng)建一個(gè)Looper對(duì)象,一個(gè)線程只能有一個(gè)Looper對(duì)象
        synchronized (this) {
            mLooper = Looper.myLooper();//獲取當(dāng)前線程的looper對(duì)象
            notifyAll();//喚醒線程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();//空方法,可重寫,在隊(duì)列循環(huán)之前執(zhí)行
        Looper.loop();//消息隊(duì)列開始循環(huán)
        mTid = -1;
    }
    ...
}

thread.start()代表著線程開啟,隨后通過mServiceLooper = thread.getLooper()獲取Looper,mServiceHandler = new ServiceHandler(mServiceLooper)并將looper放到Handler的構(gòu)造函數(shù)中。

我們都知道Handler,Looper都是屬于Android消息機(jī)制中特有的類。

IntentService的本質(zhì)是自動(dòng)新建一個(gè)線程,并為之創(chuàng)建一個(gè)Looper(Android只有主線程自帶Looper,其他線程不帶Looper,必須自己創(chuàng)建)。并通過Looper向Handler傳遞消息,完成異步操作。
最后當(dāng)Looper隊(duì)列中的消息全部傳達(dá)完之后,IntentService會(huì)自動(dòng)銷毀。

方便的不要不要的啊,把異步操作扔給IntentService,這位老哥把活干完向主線程報(bào)告了以后還會(huì)自殺,簡直是根本不要操心,一條龍給你服務(wù)到位。

再看一眼onStart方法:

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

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

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);//一般override這個(gè)方法,并將
            stopSelf(msg.arg1);
        }
    }

我們可以看到,IntentService是在onStart方法里向Handler發(fā)送消息的。

咱都清楚bindService是不跑onStart方法的。所以注意,IntentService必須使用startService。若使用bindServiceonHandleIntent方法就會(huì)失效,那就和普通Service沒區(qū)別了。

  1. 啟動(dòng)服務(wù)綁定服務(wù)先后次序問題

無非分為兩種情況:

  • 先綁定服務(wù)后開啟服務(wù)
    此時(shí)就算Activity已經(jīng)被銷毀了,服務(wù)依舊會(huì)繼續(xù)執(zhí)行。

  • 先開啟服務(wù)后綁定服務(wù)
    此時(shí)解綁服務(wù)也不會(huì)使服務(wù)銷毀,服務(wù)會(huì)繼續(xù)運(yùn)行,直到停止服務(wù)。

由此可見,啟動(dòng)服務(wù)的優(yōu)先級(jí)一直是高于綁定服務(wù)的。

這個(gè)感興趣可以用我的demo試下:https://github.com/CocoYuki/AndroidPractice/tree/master/servicetest

  1. 遠(yuǎn)程服務(wù)AIDL

好了,講遠(yuǎn)程服務(wù)之前我們先看下序列化。
為什么突然就扯到序列化了呢?因?yàn)榻酉聛硪偨Y(jié)下遠(yuǎn)程服務(wù),用遠(yuǎn)程服務(wù)傳遞序列化消息也是個(gè)很常見的場景。

Q1:什么是序列化?

表示將一個(gè)對(duì)象轉(zhuǎn)換成可存儲(chǔ)或可傳輸?shù)臓顟B(tài)。

Q2:做什么用?

為了數(shù)據(jù)的持久化和可傳遞化。簡而言之,就是對(duì)象不好操作 ,我們就把他轉(zhuǎn)成流。反序列化,就是將這個(gè)流程顛倒過來,將流轉(zhuǎn)成對(duì)象。

看下兩種序列化的區(qū)別:

  • Parcelable
  1. google專門為安卓寫的序列化接口
  2. 性能好,內(nèi)存開銷小,效率高,寫起來復(fù)雜
  3. 缺點(diǎn)是各個(gè)機(jī)型可能有差異,parcelable使用會(huì)產(chǎn)生差異,所以通訊組件之間(AIDL,INTENT)的數(shù)據(jù)傳遞,可以使用Parcelable,寫入存儲(chǔ)設(shè)備推薦使用Serializable
  • Serializable
  1. java自帶的序列化接口
  2. 他其實(shí)是一個(gè)空接口,使用簡單,是一個(gè)標(biāo)識(shí),會(huì)給類一個(gè)序列化UID
  3. 缺點(diǎn),因?yàn)槭褂梅瓷?,所以性能差,?nèi)存開銷大

Serializable沒什么好說的,非常簡單,是一個(gè)空接口。主要還是看下Parcelable,他咋用。
打開源碼一看,哇塞這也太貼心了吧,加點(diǎn)小注釋順便學(xué)習(xí)下:

 * <pre>
 * public class MyParcelable implements Parcelable {
 *     private int mData;//參數(shù)
 *      
 *     public int describeContents() {//類描述,一般不管他
 *         return 0;
 *     }
 *
 *     public void writeToParcel(Parcel out, int flags) {//序列化 :out寫入?yún)?shù),要注明參數(shù)類型 flag一般默認(rèn)是0,1代表對(duì)象需要返回,不回收
 *         out.writeInt(mData);
 *     }
 *     
 *     public static final Parcelable.Creator&lt;MyParcelable&gt; CREATOR//反序列化操作
 *             = new Parcelable.Creator&lt;MyParcelable&gt;() {
 *         public MyParcelable createFromParcel(Parcel in) {
 *             return new MyParcelable(in);
 *         }
 *
 *         public MyParcelable[] newArray(int size) {
 *             return new MyParcelable[size];
 *         }
 *     };
 *     
 *     private MyParcelable(Parcel in) {
 *         mData = in.readInt();
 *     }
 * }</pre>

google官方也是貼心的小棉襖啊,直接把怎么用放在源碼的注釋里了。

但是筆者最近在學(xué)習(xí)Kotlin的啊,有更加high的辦法。至于怎么high,可以看下我的kotlin小筆記,方法還是很簡單的!Ctrl+f關(guān)鍵詞 序列化(雖然文章很短,但是萬一以后很長呢?。?a href="http://www.itdecent.cn/p/9efe3f7a1771" target="_blank">http://www.itdecent.cn/p/9efe3f7a1771

OKOK,知道怎么用了,我們來看一下什么是遠(yuǎn)程服務(wù)。

他是一門接口定義語言,是 Android 提供的一種進(jìn)程間通信 (IPC) 機(jī)制

其實(shí)就是用來跨進(jìn)程通信的,一般都會(huì)有一個(gè)服務(wù)端提供一個(gè)服務(wù),而讓客戶端去bind這個(gè)服務(wù),而為了實(shí)現(xiàn)這個(gè)過程,必須使用aidl接口。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容