轉載請註明出處:http://blog.csdn.net/llew2011/article/details/51373243
提起Service大家都很熟悉,它乃Android四(si)大(da)組(jing)件(gang)之一。但是說起IntentService有童靴或許有點陌生,看名字感覺和Service有關連。不錯,不僅有關聯而且關係還不一般,IntentService是Service的子類,所以它也是正宗的Service,由於IntentService藉助了HandlerThread,我們今天就從源碼的角度巴拉一下IntentService及HandlerThread,看看它們是何方神聖,如果你對它們非常熟悉,請跳過本文(*^__^*) ……
開始巴拉IntentService源碼之前我們先看看它的基本用法,既然IntentService是正宗的Service,那它的用法就和Service一樣。IntentService也是一個抽象類,需要實現其抽象方法onHandleIntent()。我們先定義BackgroundService,使之繼承IntentService並實現其抽象方法onHandleIntent(),然後重寫IntentService的生命週期方法並打印日誌,代碼如下:
public class BackgroundService extends IntentService {
private static final String TAG = BackgroundService.class.getSimpleName();
public BackgroundService() {
super("TT");
Log.e(TAG, "BackgroundService() " + Thread.currentThread());
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate() " + Thread.currentThread());
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart() " + Thread.currentThread());
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() " + Thread.currentThread());
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy() " + Thread.currentThread());
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind() " + Thread.currentThread());
return super.onBind(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, "onHandleIntent() " + Thread.currentThread());
}
}
我們在重寫的部分方法中添加了日誌,主要打印當前方法名和方法執行時所在的線程名稱。然後在配置文件manifest.xml中配置BackgroundService,代碼如下:<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.llew.wb.source.intentservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.llew.wb.source.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.llew.wb.source.BackgroundService" >
</service>
</application>
</manifest>
最後在MainActivity的佈局文件activity_layout.xml中添加一個button按鈕,該按鈕用來啓動BackgroundService。佈局文件代碼如下:<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="startService"
android:text="測試IntentService" />
</FrameLayout>
定義完佈局文件後,在MainActivity中添加startIntentService()方法,代碼如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startService(View view) {
Intent action = new Intent(this, BackgroundService.class);
startService(action);
}
}
OK,一切就緒,我們運行一下看看打印結果。運行程序,輸出結果如下圖所示:根據打印結果可以確定IntentService的生命週期函數執行順序是onCreate()→onStartCommon()→onStart()→onHandleIntent()→onDestroy()。再觀察打印的線程信息發現只有onHandleIntent()的線程信息和其他函數的線程信息是不同的,也就是說onHandleIntent()所在的線程和其他函數所在的不是同一個線程,我們知道其他函數都是在主線程中執行的。所以onHandleIntent()的執行是在子線程中進行的。還有一點onDestroy()方法是在onHandleIntent()方法執行結束後才執行,因爲我們並沒有主動的調用停止Service的相關方法,所以可以猜測使IntentService停止的操作一定是在和onHandleIntent()方法所在的線程中操作的。
基於猜測,我們繼續做實驗,既然onHandleIntent()方法是在子線程中執行的,那我們就可以利用線程休眠來模擬後臺比較耗時的操作,修改onHandleIntent()方法,代碼如下:
@Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, "onHandleIntent() " + Thread.currentThread());
try {
Thread.sleep(3000);
Log.e(TAG, "sleep finish " + Thread.currentThread());
} catch (Exception e) {
e.printStackTrace();
}
}
在onHandleIntent()方法中讓其所在的線程休眠了3秒鐘,然後運行程序,輸出結果如下:根據輸出結果看到,在onHandleIntent()方法中先是打印了第一句log,等待3秒鐘後又把第二句log內容打印出來了,log打印完之後是執行Service的onDestroy()方法。我們繼續做實現,剛剛只是在onHandleIntent()的方法中模擬做了一個耗時任務,現在我們啓動多個IntentService,每一次啓動時都傳遞進來一個參數來表示每一個任務,繼續修改startService()方法,代碼如下:
public void startService(View view) {
Intent action1 = new Intent(this, BackgroundService.class);
action1.putExtra("params", "task 1");
startService(action1);
Intent action2 = new Intent(this, BackgroundService.class);
action2.putExtra("params", "task 2");
startService(action2);
Intent action3 = new Intent(this, BackgroundService.class);
action3.putExtra("params", "task 3");
startService(action3);
}
我們在startService()方法中啓動了3次BackgroundService,並在啓動時傳遞了參數。然後修改onHandleIntent()方法,代碼如下:@Override
protected void onHandleIntent(Intent intent) {
String params = intent.getStringExtra("params");
Log.e(TAG, params + " in onHandleIntent() " + Thread.currentThread());
try {
Thread.sleep(3000);
Log.e(TAG, params + " is finished " + Thread.currentThread());
} catch (Exception e) {
e.printStackTrace();
}
}
運行程序,日誌打印結果如下圖所示:觀察輸出結果發現onHandleIntent()的執行是有序的,當所有的模擬耗時任務都結束後該Service才銷燬。也就是說我們可以方便的使用IntentService來執行一些有序的並且非常耗時的異步操作,當所有的任務都執行完畢後該IntentService會主動銷燬自己,我們無需關心IntentService的銷燬。
好了,現在我們清楚了IntentService的執行流程,那接下來我們就從源碼的角度來巴拉一下IntentService,看看其內部流程,首先看一下官網對其的說明:
IntentService是一個繼承Service的用來處理異步請求的類,客戶端通過調用startService(Intent)發送請求,Service服務就會在必要的時候啓動然後在工作線程中依次處理每一個Intent,當工作線程執行完畢後Service服務就關閉自己。
這個"工作隊列處理器"是將任務從一個應用的主線程中做分離的最常用的模式,IntentService類就是該模式的經典代表。爲了使用IntentService需要先繼承IntentService然後實現其抽象方法onHandleIntent(),它在工作線程中接收發送來的所有Intent並在適當的時候結束自己。
所有的請求都會在一個單一的工作線程中被接收,工作線程可以隨意耗時而不會阻塞主線程,但是在同一時刻只能處理一個請求。
知曉了IntentService的說明後我們繼續往下看代碼,首先看一下IntentService的定義的成員變量有哪些,代碼如下:
// 提供消息隊列和
private volatile Looper mServiceLooper;
// 處理消息
private volatile ServiceHandler mServiceHandler;
// 表示工作線程的名字
private String mName;
// 是否重新發送Intent
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
IntentService中僅僅定義了4個成員變量,其中Looper類型的mServiceLooper童靴們應該很熟悉了(不熟悉也無妨我會在後續文章中從源碼的角度出發講解Android消息機制之Handler, Looper, Message和MessageQueue等),還定義了ServiceHandler類型的mServiceHandler,ServiceHandler繼承Handler,並在handleMessage()方法中調用了抽象方法onHandleIntent()方法和結束Service的stopSelf()方法。
瞭解完IntentService的成員變量後我們緊接着看一下構造方法,源碼如下:
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
IntentService的構造方法要求必須傳遞進來一個String類型的值(該值表示的是工作線程的名稱),把name賦值給了其成員變量mName。看完了構造方法後接着看IntentService的onCreate()方法,源碼如下:@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);
}
在onCreate()方法中首先調用了父類的onCreate()方法,接着創建了一個HandlerThread的實例thread,看到這裏或許有的童靴會有疑問了,HandlerThread又是何方神聖了?不必擔心,我們進入HandlerThread的源碼看看它到底是何方神聖,其源碼如下:/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly over ridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* Ask the currently running looper to quit. If the thread has not
* been started or has finished (that is if {@link #getLooper} returns
* null), then false is returned. Otherwise the looper is asked to
* quit and true is returned.
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
哦,看完HandlerThread的源碼我們就可以放心了,原來HandlerThread繼承自Thread,那也就是說HandlerThread也是一個正宗的線程類。HandlerThread類有三個成員變量,mPriority表示當前線程的優先級(默認值爲0),mTid表示線程的標識符,mLooper的作用爲當前線程添加消息隊列並循環讀取消息。
HandlerThread的成員變量了解之後,看一下其重寫的run()方法,在run()方法中先調用Process.myTid()給mTid賦值,接着調用Looper.prepare()方法爲當前線程創建一個消息隊列,創建完消息隊列後爲成員變量mLooper賦值並喚醒可能處於等待狀態的鎖機制,緊接着又設置了當前線程的優先級,最後進入Looper.loop()的方法中。
總的來看HandlerThread核心就是對外提供一個帶有Looper功能的線程,當我們創建完HandlerThread實例之後要立即調用其start()方法,如果不調用start()方法,當我們需要使用HandlerThread中的Looper時該線程就會處於掛起狀態,因爲在調用HandlerThread實例對象的getLooper()方法時,如果當前線程是isAlive()並且mLooper爲null,那麼該線程就將一直wait()下去,所以在創建完HandlerThread後要立即調用其start()方法。
看完HandlerThread源碼後我們接着看IntentService的onCreate()方法,在該方法中實例化了一個HandlerThread類型的thread,緊接着調用該thread的start()方法,然後再調用thread的getLooper()方法爲mServiceLooper賦值,最後利用mServiceLooper完成mServiceHandler的初始化工作。
看完IntentService的onCreate()方法,接着看onStartCommand()方法,源碼如下:
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
onStartCommand()函數中調用了onStart()函數,然後通過對mRedelivery的判斷決定返回START_REDELIVER_INTENT或START_NOT_STICKY,需要注意在onStartCommand()函數中只能返回以下三種類型中的一種:
- START_NOT_STICKY
如果該服務在onStartCommand()方法返回後被系統殺死,那麼知道接收到新的Intent對象,該服務纔會重新創建。這是安全的選項,用來避免在你不需要的時候運行裏的服務。 - START_STICKY
如果該服務在onStartCommand()方法返回後被系統殺死,那麼系統就會重新創建這個服務並且嘗試調用onStartCommand()方法,但是系統不會重新傳遞最後的Intent對象,系統會用一個null的Intent對象來調用onStartCommand()方法。在這個情況下除非有一些被髮送的Intent對象在等待啓動服務。這適用於不執行命令的媒體播放器(或類似的服務),它只是無限期的運行着並等待工作的到來。 - START_REDELIVER_INTENT
如果該服務在onStartCommand()方法返回後被系統殺死,那麼系統會重新創建這個服務,並且用發送給這個服務的最後一個Intent對象來調用onStartCommand()方法。任意等待的Intent對象會依次被髮送,這適合於那些應該立即恢復正在執行工作的服務,例如下載文件。
然後我們看一下onStart()方法,源碼如下:
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在onStart()方法中利用mServiceHandler發送消息並把傳遞進來的Intent等參數也一同打包發送。該消息最後在文章開頭看到的在handleMessage()方法中被處理:private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
handleMessage()方法中調用了onHandleIntent()方法,等其執行完畢後調用stopSelf()方法關閉服務。
總的來說IntentService適合在後臺執行比較耗時的,有序的異步操作並且無需我們關心何時結束該服務。HandlerThread不僅是標準的Thread而且對外提供了Looper功能,需要注意的是當創建了HandlerThread後需要立即執行其start()方法,否則該線程可能一直處於掛起狀態。
好了,到這裏有關IntentService和HandlerThread的講解就告一段落,感謝觀看。