Service和Thread的關係
不少Android初學者都可能會有這樣的疑惑,Service和Thread到底有什麼關係呢?什麼時候應該用Service,什麼時候又應該用Thread?答案可能會有點讓你吃驚,因爲Service和Thread之間沒有任何關係!
之所以有不少人會把它們聯繫起來,主要就是因爲Service的後臺概念。Thread我們大家都知道,是用於開啓一個子線程,在這裏去執行一些耗時操作就不會阻塞主線程的運行。而Service我們最初理解的時候,總會覺得它是用來處理一些後臺任務的,一些比較耗時的操作也可以放在這裏運行,這就會讓人產生混淆了。但是,如果我告訴你Service其實是運行在主線程裏的,你還會覺得它和Thread有什麼關係嗎?讓我們看一下這個殘酷的事實吧。
在MainActivity的onCreate()方法里加入一行打印當前線程id的語句:
Log.d("MyService", "MainActivity thread id is " + Thread.currentThread().getId());
然後在MyService的onCreate()方法裏也加入一行打印當前線程id的語句:
Log.d("MyService", "MyService thread id is " + Thread.currentThread().getId());
現在重新運行一下程序,並點擊Start Service按鈕,會看到如下打印日誌:
可以看到,它們的線程id完全是一樣的,由此證實了Service確實是運行在主線程裏的,也就是說如果你在Service裏編寫了非常耗時的代碼,程序必定會出現ANR的。
你可能會驚呼,這不是坑爹麼!?那我要Service又有何用呢?其實大家不要把後臺和子線程聯繫在一起就行了,這是兩個完全不同的概念。Android的後臺就是指,它的運行是完全不依賴UI的。即使Activity被銷燬,或者程序被關閉,只要進程還在,Service就可以繼續運行。比如說一些應用程序,始終需要與服務器之間始終保持着心跳連接,就可以使用Service來實現。你可能又會問,前面不是剛剛驗證過Service是運行在主線程裏的麼?在這裏一直執行着心跳連接,難道就不會阻塞主線程的運行嗎?當然會,但是我們可以在Service中再創建一個子線程,然後在這裏去處理耗時邏輯就沒問題了。
額,既然在Service裏也要創建一個子線程,那爲什麼不直接在Activity裏創建呢?這是因爲Activity很難對Thread進行控制,當Activity被銷燬之後,就沒有任何其它的辦法可以再重新獲取到之前創建的子線程的實例。而且在一個Activity中創建的子線程,另一個Activity無法對其進行操作。但是Service就不同了,所有的Activity都可以與Service進行關聯,然後可以很方便地操作其中的方法,即使Activity被銷燬了,之後只要重新與Service建立關聯,就又能夠獲取到原有的Service中Binder的實例。因此,使用Service來處理後臺任務,Activity就可以放心地finish,完全不需要擔心無法對後臺任務進行控制的情況。
一個比較標準的Service就可以寫成:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 開始執行後臺任務
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 執行具體的下載任務
}
}).start();
}
}