1. 程式人生 > >【轉】Android開發:Service和Thread的關係

【轉】Android開發: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

 

 

Service幾乎都是在後臺執行的,一直以來它都是默默地做著辛苦的工作。但是Service的系統優先順序還是比較低的,當系統出現記憶體不足情況時,就有可能會回收掉正在後臺執行的Service。如果你希望Service可以一直保持執行狀態,而不會由於系統記憶體不足的原因導致被回收,就可以考慮使用前臺Service。前臺Service和普通Service最大的區別就在於,它會一直有一個正在執行的圖示在系統的狀態列顯示,下拉狀態列後可以看到更加詳細的資訊,非常類似於通知的效果。當然有時候你也可能不僅僅是為了防止Service被回收才使用前臺Service,有些專案由於特殊的需求會要求必須使用前臺Service,比如說墨跡天氣,它的Service在後臺更新天氣資料的同時,還會在系統狀態列一直顯示當前天氣的資訊,如下圖所示:

                                                   

那麼我們就來看一下如何才能建立一個前臺Service吧,其實並不複雜,修改MyService中的程式碼,如下所示:

public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    private MyBinder mBinder = new MyBinder();  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Notification notification = new Notification(R.drawable.ic_launcher,  
                "有通知到來", System.currentTimeMillis());  
        Intent notificationIntent = new Intent(this, MainActivity.class);  
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,  
                notificationIntent, 0);  
        notification.setLatestEventInfo(this, "這是通知的標題", "這是通知的內容",  
                pendingIntent);  
        startForeground(1, notification);  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    .........  
  
}  

  


這裡只是修改了MyService中onCreate()方法的程式碼。可以看到,我們首先建立了一個Notification物件,然後呼叫了它的setLatestEventInfo()方法來為通知初始化佈局和資料,並在這裡設定了點選通知後就開啟MainActivity。然後呼叫startForeground()方法就可以讓MyService變成一個前臺Service,並會將通知的圖片顯示出來。

 

現在重新執行一下程式,並點選Start Service或Bind Service按鈕,MyService就會以前臺Service的模式啟動了,並且在系統狀態列會彈出一個通欄圖示,下拉狀態列後可以看到通知的詳細內容,如下圖所示。

                                                   

 

from:https://blog.csdn.net/daniel80110_1020/article/details/59110946