編輯:關於Android編程
提起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,代碼如下:
最後在MainActivity的布局文件activity_layout.xml中添加一個button按鈕,該按鈕用來啟動BackgroundService。布局文件代碼如下:
<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"></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
然後我們看一下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的講解就告一段落,感謝觀看。
基礎介紹異步消息處理線程是指,線程在啟動後會進入一個無線循環體中,沒循環一次,從內部的消息隊列中取出一個一個消息,並回調相應的消息處理函數,執行完一個消息後則繼續循環。如
Android Studio安裝更新終極解決方式之前寫過一篇Android SDK無法更新的博文,其實該方式對Android Studio同樣有效,大伙可以下載網盤中分享
先看效果圖: 首先,你得寫一個類我們命名為CornerListView[java]復制代碼 代碼如下:/** * 圓角ListView示例 * @De
1.寫在前面的話今天我們來學習Android中如何使用Sqlite以及性能優化。2.Android平台下數據庫相關類SQLiteOpenHelper 抽象類:通過從此類繼