原作者:[在一顆大大大榕樹下
原鏈接:[ 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
-
Service和線程的區(qū)別和場景
我們都知道,Service和線程呢,都是在后臺(tái)運(yùn)行的,那么google為什么要為android系統(tǒng)創(chuàng)造出Service這么一個(gè)組件呢?我們先來看下線程和Service的特點(diǎn)。
Thread
程序最小的執(zhí)行單元,他是分配給CPU的基本單位
生命周期
- 新建(new Thread)
- 就緒 (線程已經(jīng)啟動(dòng),等待CPU資源)
- 運(yùn)行(run已經(jīng)獲得資源)
- 死亡(執(zhí)行完成或被殺死)
- 阻塞(因?yàn)槟撤N原因線程讓出cpu資源,就會(huì)進(jìn)入阻塞狀態(tài))
這里可以看出來一個(gè)致命的問題
線程一但run了起來,就和Activity失去關(guān)聯(lián)了。
即使Activity被干掉了,Thread依舊能快樂的執(zhí)行下去。
Thread是無法控制的。
google:這問題很大。

OK,于是我們的Service就誕生了。
-
管理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
- service和IntentService有什么區(qū)別
首先得劃個(gè)重點(diǎn):Service是在主線程中運(yùn)行的,所以不能做耗時(shí)操作,會(huì)報(bào)ANR異常

不能做耗時(shí)操作,就意味著無法替代Thread的功能,那這Service啥意義啊?
這就是IntentService和Service區(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。若使用bindService,onHandleIntent方法就會(huì)失效,那就和普通Service沒區(qū)別了。
- 啟動(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
- 遠(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
- google專門為安卓寫的序列化接口
- 性能好,內(nèi)存開銷小,效率高,寫起來復(fù)雜
- 缺點(diǎn)是各個(gè)機(jī)型可能有差異,parcelable使用會(huì)產(chǎn)生差異,所以通訊組件之間(AIDL,INTENT)的數(shù)據(jù)傳遞,可以使用Parcelable,寫入存儲(chǔ)設(shè)備推薦使用Serializable
- Serializable
- java自帶的序列化接口
- 他其實(shí)是一個(gè)空接口,使用簡單,是一個(gè)標(biāo)識(shí),會(huì)給類一個(gè)序列化UID
- 缺點(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<MyParcelable> CREATOR//反序列化操作
* = new Parcelable.Creator<MyParcelable>() {
* 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接口。