欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Android中IntentService的使用方法

 更新時(shí)間:2015年12月16日 10:55:46   投稿:lijiao  
這篇文章主要介紹了Android中IntentService的使用方法,需要的朋友可以參考下

為什么我們需要IntentService ?

Android中的IntentService是繼承自Service類(lèi)的,在我們討論IntentService之前,我們先想一下Service的特點(diǎn): Service的回調(diào)方法(onCreate、onStartCommand、onBind、onDestroy)都是運(yùn)行在主線(xiàn)程中的。當(dāng)我們通過(guò)startService啟動(dòng)Service之后,我們就需要在Service的onStartCommand方法中寫(xiě)代碼完成工作,但是onStartCommand是運(yùn)行在主線(xiàn)程中的,如果我們需要在此處完成一些網(wǎng)絡(luò)請(qǐng)求或IO等耗時(shí)操作,這樣就會(huì)阻塞主線(xiàn)程UI無(wú)響應(yīng),從而出現(xiàn)ANR現(xiàn)象。為了解決這種問(wèn)題,最好的辦法就是在onStartCommand中創(chuàng)建一個(gè)新的線(xiàn)程,并把耗時(shí)代碼放到這個(gè)新線(xiàn)程中執(zhí)行??梢詤⒖贾暗奈恼?a target="_blank" href="http://www.dbjr.com.cn/article/76476.htm">《Android通過(guò)startService實(shí)現(xiàn)文件批量下載》,這篇文章在onStartCommand中開(kāi)啟了新的線(xiàn)程作為工作線(xiàn)程去執(zhí)行網(wǎng)絡(luò)請(qǐng)求,所以這樣不會(huì)阻塞主線(xiàn)程。由此看來(lái),創(chuàng)建一個(gè)帶有工作線(xiàn)程的Service是一種很常見(jiàn)的需求(因?yàn)楣ぷ骶€(xiàn)程不會(huì)阻塞主線(xiàn)程),所以Android為了簡(jiǎn)化開(kāi)發(fā)帶有工作線(xiàn)程的Service,Android額外開(kāi)發(fā)了一個(gè)類(lèi)——–IntentService。

IntentService的特點(diǎn)

IntentService具有以下特點(diǎn):

  • 1. IntentService自帶一個(gè)工作線(xiàn)程,當(dāng)我們的Service需要做一些可能會(huì)阻塞主線(xiàn)程的工作的時(shí)候可以考慮使用IntentService。
  • 2. 我們需要將要做的實(shí)際工作放入到IntentService的onHandleIntent回到方法中,當(dāng)我們通過(guò)startService(intent)啟動(dòng)了IntentService之后,最終Android Framework會(huì)回調(diào)其onHandleIntent方法,并將intent傳入該方法,這樣我們就可以根據(jù)intent去做實(shí)際工作,并且onHandleIntent運(yùn)行在IntentService所持有的工作線(xiàn)程中,而非主線(xiàn)程。
  • 3. 當(dāng)我們通過(guò)startService多次啟動(dòng)了IntentService,這會(huì)產(chǎn)生多個(gè)job,由于IntentService只持有一個(gè)工作線(xiàn)程,所以每次onHandleIntent只能處理一個(gè)job。面多多個(gè)job,IntentService會(huì)如何處理?處理方式是one-by-one,也就是一個(gè)一個(gè)按照先后順序處理,先將intent1傳入onHandleIntent,讓其完成job1,然后將intent2傳入onHandleIntent,讓其完成job2…這樣直至所有job完成,所以我們IntentService不能并行的執(zhí)行多個(gè)job,只能一個(gè)一個(gè)的按照先后順序完成,當(dāng)所有job完成的時(shí)候IntentService就銷(xiāo)毀了,會(huì)執(zhí)行onDestroy回調(diào)方法。

如何使用IntentService ?

《Android通過(guò)startService實(shí)現(xiàn)文件批量下載》一文中,我們演示了如何通過(guò)Service批量下載文章,現(xiàn)在在本文中我們還是要演示如何批量下載文章,只不過(guò)是用IntentService完成這項(xiàng)工作。

系統(tǒng)界面如下:

界面很簡(jiǎn)單,就一個(gè)按鈕“批量下載文章”,通過(guò)該Activity上的按鈕啟動(dòng)DownloadService。

代碼如下:

package com.ispring.startservicedemo;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class DownloadIntentService extends IntentService {

 public DownloadIntentService(){
  super("Download");
  Log.i("DemoLog", "DownloadIntentService構(gòu)造函數(shù), Thread: " + Thread.currentThread().getName());
 }

 @Override
 public void onCreate() {
  super.onCreate();
  Log.i("DemoLog", "DownloadIntentService -> onCreate, Thread: " + Thread.currentThread().getName());
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  Log.i("DemoLog", "DownloadIntentService -> onStartCommand, Thread: " + Thread.currentThread().getName() + " , startId: " + startId);
  return super.onStartCommand(intent, flags, startId);
 }

 @Override
 protected void onHandleIntent(Intent intent) {
  HttpURLConnection conn = null;
  InputStream is = null;
  String blogUrl = intent.getStringExtra("url");
  String blogName = intent.getStringExtra("name");
  try{
   //下載指定的文件
   URL url = new URL(blogUrl);
   conn = (HttpURLConnection)url.openConnection();
   if(conn != null){
    //我們?cè)诖颂幍玫剿螺d文章的輸入流,可以將其以文件的形式寫(xiě)入到存儲(chǔ)卡上面或
    //將其讀取出文本顯示在App中
    is = conn.getInputStream();
   }
  }catch (MalformedURLException e){
   e.printStackTrace();
  }catch (IOException e){
   e.printStackTrace();
  }finally {
   if(conn != null){
    conn.disconnect();
   }
  }
  Log.i("DemoLog", "DownloadIntentService -> onHandleIntent, Thread: " + Thread.currentThread().getName() + ", 《" + blogName + "》下載完成");
 }

 @Override
 public void onDestroy() {
  super.onDestroy();
  Log.i("DemoLog", "DownloadIntentService -> onDestroy, Thread: " + Thread.currentThread().getName());
 }
}

DownloadActivity的代碼如下:

package com.ispring.startservicedemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class DownloadActivity extends Activity implements Button.OnClickListener {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_download);
 }

 @Override
 public void onClick(View v) {
  List<String> list = new ArrayList<>();
  list.add("Android通過(guò)startService播放背景音樂(lè);http://www.dbjr.com.cn/article/76479.htm");
  Iterator iterator = list.iterator();

  while (iterator.hasNext()){
   String str = (String)iterator.next();
   String[] splits = str.split(";");
   String name = splits[0];
   String url = splits[1];
   Intent intent = new Intent(this, DownloadIntentService.class);
   intent.putExtra("name", name);
   intent.putExtra("url", url);
   //啟動(dòng)IntentService
   startService(intent);
  }
 }
}

當(dāng)我們單擊了按鈕“批量下載文章”時(shí),我們會(huì)多次調(diào)用Activity的startService方法,其中我們?cè)谄鋮?shù)intent中存儲(chǔ)了文章名name以及文章的地址url,由于我們多次調(diào)用了startService方法,所以會(huì)批量下載文章。

點(diǎn)擊按鈕后,控制臺(tái)運(yùn)行結(jié)果如下所示:

通過(guò)以上的輸出結(jié)果我們可以發(fā)現(xiàn),DownloadIntentService的onCreate、onStartCommand、onDestroy回調(diào)方法都是運(yùn)行在主線(xiàn)程中的,而onHandleIntent是運(yùn)行在工作線(xiàn)程IntentService[Download]中的,這驗(yàn)證了我們上面所說(shuō)的IntentService的第一個(gè)和第二個(gè)特點(diǎn)。

通過(guò)上面的輸出結(jié)果我們還會(huì)發(fā)現(xiàn),在我們連續(xù)調(diào)用了五次startService(intent)之后,onStartCommand依次被調(diào)用了五次,然后依次執(zhí)行了onHandleIntent五次,這樣就依次完成了job,當(dāng)最后一個(gè)job完成,也就是在最后一次onHandleIntent調(diào)用完成之后,整個(gè)IntentService的工作都完成,執(zhí)行onDestroy回調(diào)方法,IntentService銷(xiāo)毀。

IntentService工作原理及源碼解析

在上面我們已經(jīng)介紹了IntentService的特點(diǎn)以及如何使用,那么你可能會(huì)疑問(wèn)Android是如何將調(diào)度這些intent將其傳入onHandleIntent完成工作的,其實(shí)IntentService的工作原理很簡(jiǎn)單,將intent轉(zhuǎn)換為Message并放到消息隊(duì)列中,然后讓Handler依次從中取出Message對(duì)其進(jìn)行處理。

IntentService的源碼如下:

package android.app;

import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;

public abstract class IntentService extends Service {
 private volatile Looper mServiceLooper;
 private volatile ServiceHandler mServiceHandler;
 private String mName;
 private boolean mRedelivery;

 private final class ServiceHandler extends Handler {
  public ServiceHandler(Looper looper) {
   super(looper);
  }

  @Override
  public void handleMessage(Message msg) {
   //在工作線(xiàn)程中調(diào)用onHandleIntent,確保onHandleIntent不會(huì)阻塞主線(xiàn)程
   onHandleIntent((Intent)msg.obj);
   //在執(zhí)行完了onHandleIntent之后,我們需要調(diào)用stopSelf(startId)聲明某個(gè)job完成了
   //當(dāng)所有job完成的時(shí)候,Android就會(huì)回調(diào)onDestroy方法,銷(xiāo)毀IntentService
   stopSelf(msg.arg1);
  }
 }

 public IntentService(String name) {
  //此處的name將用作線(xiàn)程名稱(chēng)
  super();
  mName = name;
 }

 public void setIntentRedelivery(boolean enabled) {
  mRedelivery = enabled;
 }

 @Override
 public void onCreate() {
  super.onCreate();
  //創(chuàng)建HandlerThread,利用mName作為線(xiàn)程名稱(chēng),HandlerThread是IntentService的工作線(xiàn)程
  HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
  thread.start();

  mServiceLooper = thread.getLooper();
  //將創(chuàng)建的HandlerThread所綁定的looper對(duì)象傳遞給ServiceHandler,
  //這樣我們創(chuàng)建的Handler就和HandlerThread通過(guò)消息隊(duì)列綁定在了一起
  mServiceHandler = new ServiceHandler(mServiceLooper);
 }

 @Override
 public void onStart(Intent intent, int startId) {
  //在此方法中創(chuàng)建Message對(duì)象,并將intent作為Message的obj參數(shù),
  //這樣Message與Intent就關(guān)聯(lián)起來(lái)了
  Message msg = mServiceHandler.obtainMessage();
  msg.arg1 = startId;
  msg.obj = intent;
  //將關(guān)聯(lián)了Intent信息的Message發(fā)送給Handler
  mServiceHandler.sendMessage(msg);
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  //IntentService重寫(xiě)了onStartCommand回調(diào)方法:在內(nèi)部調(diào)用onStart回調(diào)方法
  //所以我們?cè)诶^承IntentService時(shí),不應(yīng)該再覆寫(xiě)該方法,即便覆蓋該方法,我們也應(yīng)該調(diào)用super.onStartCommand()
  onStart(intent, startId);
  return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
 }

 @Override
 public void onDestroy() {
  //在onDestroy方法中調(diào)用了Handler的quit方法,該方法會(huì)終止消息循環(huán)
  mServiceLooper.quit();
 }

 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }

 protected abstract void onHandleIntent(Intent intent);
}

我對(duì)上面的代碼已經(jīng)加了很多注釋?zhuān)嘈糯蠹抑苯涌创a就能理解IntentService是如何運(yùn)作的了。

IntentService繼承自Service類(lèi),并且IntentService重寫(xiě)了onCreate、onStartCommand、onStart、onDestroy回調(diào)方法,并且IntentService還添加了一個(gè)onHandleIntent回調(diào)方法。下面我們依次解釋這幾個(gè)方法在IntentService的作用。

onCreate: 在onCreate回調(diào)方法中,利用mName作為線(xiàn)程名稱(chēng),創(chuàng)建HandlerThread,HandlerThread是IntentService的工作線(xiàn)程。HandlerThread在執(zhí)行了start方法之后,其本身就關(guān)聯(lián)了消息隊(duì)列和Looper,并且消息隊(duì)列開(kāi)始循環(huán)起來(lái)。

onStartCommand: IntentService重寫(xiě)了onStartCommand回調(diào)方法:在內(nèi)部調(diào)用onStart回調(diào)方法。

onStart: 在onStart方法中創(chuàng)建Message對(duì)象,并將intent作為Message的obj參數(shù),這樣Message與Intent就關(guān)聯(lián)起來(lái)了,然后通過(guò)Handler的sendMessage方法將關(guān)聯(lián)了Intent信息的Message發(fā)送給Handler。

onHandleIntent: 當(dāng)在onStart方法中,通過(guò)sendMessage方法將Message放入到Handler所關(guān)聯(lián)的消息隊(duì)列中后,Handler所關(guān)聯(lián)的Looper對(duì)象會(huì)從消息隊(duì)列中取出一個(gè)Message,然后將其傳入Handler的handleMessage方法中,在handleMessage方法中首先通過(guò)Message的obj獲取到了原始的Intent對(duì)象,然后將其作為參數(shù)傳給了onHandleIntent方法讓其執(zhí)行。handleMessage方法是運(yùn)行在HandlerThread的,所以onHandleIntent也是運(yùn)行在工作線(xiàn)程中的。在執(zhí)行完了onHandleIntent之后,我們需要調(diào)用stopSelf(startId)聲明某個(gè)job完成了。當(dāng)所有job完成的時(shí)候,Android就會(huì)回調(diào)onDestroy方法,銷(xiāo)毀IntentService。

onDestroy: 當(dāng)所有job完成的時(shí)候,Service會(huì)銷(xiāo)毀并執(zhí)行其onDestroy回調(diào)方法。在該方法中,調(diào)用了Handler的quit方法,該方法會(huì)終止消息循環(huán)。

總結(jié)

IntentService可以在工作線(xiàn)程中完成工作而不阻塞主線(xiàn)程,但是IntentService不能并行處理多個(gè)job,只能依次處理,一個(gè)接一個(gè),當(dāng)所有的job完成后,會(huì)自動(dòng)執(zhí)行onDestroy方法而無(wú)需我們自己調(diào)用stopSelf()或stopSelf(startId)方法。IntentService并不神秘,只是Android對(duì)一種常見(jiàn)開(kāi)發(fā)方式的封裝,便于開(kāi)發(fā)人員減少開(kāi)發(fā)工作量。 IntentService是個(gè)助手類(lèi),如果Android沒(méi)有提供該類(lèi)也沒(méi)什么,我們自己也可以寫(xiě)一個(gè)類(lèi)似的。IntentService之余Service,類(lèi)似于HandlerThread之于Handler。

希望本文對(duì)大家理解IntentService有所幫助。

相關(guān)文章

最新評(píng)論