淺談IntentService原理分析
//繼承IntentService,並取個名兒 class SampleIntentService : IntentService("SampleIntentService") { //重寫onHandleIntent override fun onHandleIntent(intent: Intent?) { //進行耗時操作,這裡是工作執行緒 } //別忘了在mainfest裡註冊哦 } 複製程式碼
emmmm,IntentService就這麼簡單,不過這只是用法哦。
二.IntentService結構組成
要想了解原始碼,別單單看別人的技術文章,看是沒有用的,最好把原始碼開啟,邊看邊對著原始碼瞭解,那樣能理解的快些。
- 看看繼承類
這裡看到IntentService是繼承Service public abstract class IntentService extends Service 複製程式碼
- 看看構造方法
/** * Creates an IntentService.Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */ 這裡可以看到剛才為嘛給IntentService帶個String的引數了,原來給是工作執行緒取名字呀 public IntentService(String name) { super(); mName = name; } 複製程式碼
- 因為是繼承Service的,所以我們可以看看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(); //這裡建立工作執行緒,所以使用intentService為什麼不需要建立工作執行緒 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); //獲取looper,與handler產生聯動,實現訊息的通訊 mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } 複製程式碼
這裡小結下(IntentService裡有什麼東西)
- 建立了一個具有looper的工作執行緒
- 建立了一個執行緒通訊的Handler
- 把具有looper的執行緒跟handler聯動
三.IntentService具體實現
當一個IntentService開啟時,先呼叫onCreate方法,然後會呼叫onStartCommand(),然後呼叫onStart(),儲存message,handler傳送訊息,handleMessage()處理訊息,然後onHandleIntent交給子類去實現,等message都處理完了,stopSelf(msg.arg1)停止服務
//繼承Handler類 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); } } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; //這裡要注意,儲存這個startId是有用的,後面會講到 msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 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(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); } 複製程式碼
這裡有個關鍵,每次start(),都會把message儲存到messagequeue佇列中,messagequeue是單執行緒佇列,那麼intentService是怎麼知道任務全部完成才會去取消任務的呢? 可以看看ActiveServices原始碼 關鍵程式碼
boolean stopServiceTokenLocked(ComponentName className, IBinder token, int startId) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className + " " + token + " startId=" + startId); ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId()); if (r != null) { if (startId >= 0) { // Asked to only stop if done with all work.Note that // to avoid leaks, we will take this as dropping all // start items up to and including this one. ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); if (si != null) { while (r.deliveredStarts.size() > 0) { ServiceRecord.StartItem cur = r.deliveredStarts.remove(0); cur.removeUriPermissionsLocked(); if (cur == si) { break; } } } if (r.getLastStartId() != startId) { return false; } if (r.deliveredStarts.size() > 0) { Slog.w(TAG, "stopServiceToken startId " + startId + " is last, but have " + r.deliveredStarts.size() + " remaining args"); } } synchronized (r.stats.getBatteryStats()) { r.stats.stopRunningLocked(); } r.startRequested = false; if (r.tracker != null) { r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis()); } r.callStart = false; final long origId = Binder.clearCallingIdentity(); bringDownServiceIfNeededLocked(r, false, false); Binder.restoreCallingIdentity(origId); return true; } return false; } 複製程式碼
ActiveServices裡的stopServiceTokenLocked()裡的判斷r.getLastStartId()!= startId,來判斷當前startId是不是最後一個startId,是就執行r.stats.stopRunningLocked()來終止
課外知識 Handler是負責執行緒間的通訊的 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. */ 是一個擁有looper的執行緒類,這個looper可以用來跟handler來互動,但一定要用start方法來開啟 複製程式碼