特點(diǎn)
- 它本質(zhì)是一種特殊的Service,繼承自Service并且本身就是一個(gè)抽象類
- 它可以用于在后臺執(zhí)行耗時(shí)的異步任務(wù)鸥印,當(dāng)任務(wù)完成后會自動停止
- 它擁有較高的優(yōu)先級书闸,不易被系統(tǒng)殺死(繼承自Service的緣故)翩概,因此比較適合執(zhí)行一些高優(yōu)先級的異步任務(wù)
- 它內(nèi)部通過HandlerThread和Handler實(shí)現(xiàn)異步操作
- 創(chuàng)建IntentService時(shí),只需實(shí)現(xiàn)onHandleIntent和構(gòu)造方法,onHandleIntent為異步方法臭增,可以執(zhí)行耗時(shí)操作
使用實(shí)例
public class MyIntentService extends IntentService {
public static final String DOWNLOAD_URL="download_url";
public static final String INDEX_FLAG="index_flag";
public static UpdateUI updateUI;
public static void setUpdateUI(UpdateUI updateUIInterface){
updateUI=updateUIInterface;
}
public MyIntentService(){
super("MyIntentService");
}
/**
* 實(shí)現(xiàn)異步任務(wù)的方法
* @param intent Activity傳遞過來的Intent,數(shù)據(jù)封裝在intent中
*/
@Override
protected void onHandleIntent(Intent intent) {
//在子線程中進(jìn)行網(wǎng)絡(luò)請求
Bitmap bitmap=downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
Message msg1 = new Message();
msg1.what = intent.getIntExtra(INDEX_FLAG,0);
msg1.obj =bitmap;
//通知主線程去更新UI
if(updateUI!=null){
updateUI.updateUI(msg1);
}
//mUIHandler.sendMessageDelayed(msg1,1000);
LogUtils.e("onHandleIntent");
}
//----------------------重寫一下方法僅為測試------------------------------------------
@Override
public void onCreate() {
LogUtils.e("onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
LogUtils.e("onStart");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.e("onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
LogUtils.e("onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
LogUtils.e("onBind");
return super.onBind(intent);
}
public interface UpdateUI{
void updateUI(Message message);
}
private Bitmap downloadUrlBitmap(String urlString) {
HttpURLConnection urlConnection = null;
BufferedInputStream in = null;
Bitmap bitmap=null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
bitmap= BitmapFactory.decodeStream(in);
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
}
通過代碼可以看出横辆,我們繼承了IntentService撇他,這里有兩個(gè)方法是必須實(shí)現(xiàn)的,一個(gè)是構(gòu)造方法狈蚤,必須傳遞一個(gè)線程名稱的字符串逆粹,另外一個(gè)就是進(jìn)行異步處理的方法onHandleIntent(Intent intent) 方法,其參數(shù)intent可以附帶從activity傳遞過來的數(shù)據(jù)炫惩。這里我們的案例主要利用onHandleIntent實(shí)現(xiàn)異步下載圖片僻弹,然后通過回調(diào)監(jiān)聽的方法把下載完的bitmap放在message中回調(diào)給Activity(當(dāng)然也可以使用廣播完成),最后通過Handler去更新UI他嚷。下面再來看看Acitvity的代碼:
public class IntentServiceActivity extends Activity implements MyIntentService.UpdateUI{
/**
* 圖片地址集合
*/
private String url[] = {
"http://img.blog.csdn.net/20160903083245762",
"http://img.blog.csdn.net/20160903083252184",
"http://img.blog.csdn.net/20160903083257871",
"http://img.blog.csdn.net/20160903083257871",
"http://img.blog.csdn.net/20160903083311972",
"http://img.blog.csdn.net/20160903083319668",
"http://img.blog.csdn.net/20160903083326871"
};
private static ImageView imageView;
private static final Handler mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
imageView.setImageBitmap((Bitmap) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
imageView = (ImageView) findViewById(R.id.image);
Intent intent = new Intent(this,MyIntentService.class);
for (int i=0;i<7;i++) {//循環(huán)啟動任務(wù)
intent.putExtra(MyIntentService.DOWNLOAD_URL,url[i]);
intent.putExtra(MyIntentService.INDEX_FLAG,i);
startService(intent);
}
MyIntentService.setUpdateUI(this);
}
//必須通過Handler去更新蹋绽,該方法為異步方法,不可更新UI
@Override
public void updateUI(Message message) {
mUIHandler.sendMessageDelayed(message,message.what * 1000);
}
}
代碼比較簡單筋蓖,通過for循環(huán)多次去啟動IntentService卸耘,然后去下載圖片,注意即使我們多次啟動IntentService粘咖,但I(xiàn)ntentService的實(shí)例只有一個(gè)蚣抗,這跟傳統(tǒng)的Service是一樣的,最終IntentService會去調(diào)用onHandleIntent執(zhí)行異步任務(wù)瓮下。這里可能我們還會擔(dān)心for循環(huán)去啟動任務(wù)翰铡,而實(shí)例又只有一個(gè),那么任務(wù)會不會被覆蓋掉呢讽坏?其實(shí)是不會的锭魔,因?yàn)镮ntentService真正執(zhí)行異步任務(wù)的是HandlerThread+Handler,每次啟動都會把下載圖片的任務(wù)添加到依附的消息隊(duì)列中路呜,最后由HandlerThread+Handler去執(zhí)行.
源碼解析
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);
}
當(dāng)?shù)谝粏覫ntentService時(shí)迷捧,它的onCreate方法將會被調(diào)用,其內(nèi)部會去創(chuàng)建一個(gè)HandlerThread并啟動它胀葱,接著創(chuàng)建一個(gè)ServiceHandler(繼承Handler)漠秋,傳入HandlerThread的Looper對象,這樣ServiceHandler就變成可以處理異步線程的執(zhí)行類了(因?yàn)長ooper對象與HandlerThread綁定抵屿,而HandlerThread又是一個(gè)異步線程庆锦,我們把HandlerThread持有的Looper對象傳遞給Handler后,ServiceHandler內(nèi)部就持有異步線程的Looper晌该,自然就可以執(zhí)行異步任務(wù)了)肥荔,那么IntentService是怎么啟動異步任務(wù)的呢绿渣?其實(shí)IntentService啟動后還會去調(diào)用onStartCommand方法,而onStartCommand方法又會去調(diào)用onStart方法燕耿,我們看看它們的源碼:
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = 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(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
從源碼我們可以看出中符,在onStart方法中,IntentService通過mServiceHandler的sendMessage方法發(fā)送了一個(gè)消息誉帅,這個(gè)消息將會發(fā)送到HandlerThread中進(jìn)行處理(因?yàn)镠andlerThread持有Looper對象淀散,所以其實(shí)是Looper從消息隊(duì)列中取出消息進(jìn)行處理,然后調(diào)用mServiceHandler的handleMessage方法)蚜锨,我們看看ServiceHandler的源碼:
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);
}
}
這里其實(shí)也說明onHandleIntent確實(shí)是一個(gè)異步處理方法(ServiceHandler本身就是一個(gè)異步處理的handler類)档插,在onHandleIntent方法執(zhí)行結(jié)束后,IntentService會通過 stopSelf(int startId)方法來嘗試停止服務(wù)亚再。這里采用stopSelf(int startId)而不是stopSelf()來停止服務(wù)郭膛,是因?yàn)閟topSelf()會立即停止服務(wù),而stopSelf(int startId)會等待所有消息都處理完后才終止服務(wù)氛悬。最后看看onHandleIntent方法的聲明:
protected abstract void onHandleIntent(Intent intent);
到此我們就知道了IntentService的onHandleIntent方法是一個(gè)抽象方法则剃,所以我們在創(chuàng)建IntentService時(shí)必須實(shí)現(xiàn)該方法,通過上面一系列的分析可知如捅,onHandleIntent方法也是一個(gè)異步方法棍现。這里要注意的是如果后臺任務(wù)只有一個(gè)的話,onHandleIntent執(zhí)行完镜遣,服務(wù)就會銷毀己肮,但如果后臺任務(wù)有多個(gè)的話,onHandleIntent執(zhí)行完最后一個(gè)任務(wù)時(shí)悲关,服務(wù)才銷毀谎僻。最后我們要知道每次執(zhí)行一個(gè)后臺任務(wù)就必須啟動一次IntentService,而IntentService內(nèi)部則是通過消息的方式發(fā)送給HandlerThread的坚洽,然后由Handler中的Looper來處理消息戈稿,而Looper是按順序從消息隊(duì)列中取任務(wù)的,也就是說IntentService的后臺任務(wù)時(shí)順序執(zhí)行的讶舰,當(dāng)有多個(gè)后臺任務(wù)同時(shí)存在時(shí),這些后臺任務(wù)會按外部調(diào)用的順序排隊(duì)執(zhí)行需了,我們前面的使用案例也很好說明了這點(diǎn)跳昼。