前幾篇文章帶領(lǐng)大家對(duì)HandlerThread的用法及原理進(jìn)行了深入探索扩氢,為了鞏固大家對(duì)HandlerThread的認(rèn)識(shí),讓大家對(duì)HandlerThread的理解更上一層臺(tái)階,本篇文章將向大家介紹與HandlerThread關(guān)系密切的一大神器---IntentService,大家可以帶著以下三個(gè)問(wèn)題去看接下來(lái)的文章:1.為什么說(shuō)IntentService和HandlerThread有著密切的關(guān)系? 2.為什么IntentService可被稱(chēng)作Android的一大神器微宝,它和傳統(tǒng)的Service有何區(qū)別添怔? 3. IntentService的底層實(shí)現(xiàn)原理是怎樣的?
我們知道徽龟,Service中的代碼是運(yùn)行在主線程中的叮姑,如果在Service中直接進(jìn)行耗時(shí)操作,就很有可能出現(xiàn)ANR(Application Not Responding)据悔。所以传透,我們想在Service中進(jìn)行耗時(shí)操作耘沼,耗時(shí)邏輯一定要放在子線程中運(yùn)行,代碼如下:
public class FirstService extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public int onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable(){
@Override
public void run(){
//處理耗時(shí)邏輯
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
上面的服務(wù)一旦啟動(dòng)后會(huì)一直運(yùn)行朱盐,必須調(diào)用stopService()或stopSelf()才可以讓服務(wù)停止耕拷,代碼如下:
public class SecondService extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public int onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable(){
@Override
public void run(){
//處理耗時(shí)邏輯
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
上面的寫(xiě)法雖然并不復(fù)雜,但是還是會(huì)有不少程序員在Service中處理耗時(shí)邏輯時(shí)忘記開(kāi)啟子線程或者忘記停止Service托享,Android中為了解決
這兩個(gè)問(wèn)題骚烧,提升開(kāi)發(fā)人員的效率,引入了IntentService這一神器闰围!
我們先來(lái)看一下IntentService在官方文檔中的介紹:
文檔中講得很清楚赃绊,IntentService繼承自Service類(lèi),能夠用來(lái)處理異步的請(qǐng)求羡榴,客戶(hù)端可通過(guò)startService(Intent)來(lái)發(fā)送請(qǐng)求碧查,Service會(huì)根據(jù)需要被啟動(dòng),使用一個(gè)工作者線程輪流處理每個(gè)請(qǐng)求校仑,并且當(dāng)它處理完所有的請(qǐng)求后會(huì)停止它自身忠售。
IntentService中有一個(gè)很重要的方法: onHandleIntent,看一下官方文檔對(duì)它的介紹:
當(dāng)某個(gè)請(qǐng)求需要處理時(shí),這個(gè)方法會(huì)在工作者線程被調(diào)用迄沫,一次僅僅會(huì)有一個(gè)請(qǐng)求被處理稻扬,但是處理過(guò)程會(huì)運(yùn)行在工作者線程(獨(dú)立于其他應(yīng)用程序邏輯運(yùn)行)。因此羊瘩,如果某段代碼需要執(zhí)行很長(zhǎng)時(shí)間泰佳,它會(huì)阻塞住其他提交到該IntentService的請(qǐng)求,但是不會(huì)阻塞住其他任何東西尘吗。當(dāng)所有的請(qǐng)求被處理完成之后逝她,IntentService會(huì)停止它自身,因此你不應(yīng)該手動(dòng)調(diào)用stopSelf()方法睬捶。
說(shuō)了這么多黔宛,大家對(duì)IntentService的認(rèn)識(shí)可能還是很模糊,下面通過(guò)一個(gè)具體的例子讓大家深入地體會(huì)下:
我們模擬一個(gè)多張圖片下載的場(chǎng)景擒贸,點(diǎn)擊“Add Download Task”按鈕可以增加圖片下載任務(wù)臀晃,下方也會(huì)增加一條記錄代表新增的下載任務(wù),當(dāng)下載任務(wù)完成時(shí)酗宋,相應(yīng)的任務(wù)記錄也會(huì)進(jìn)行更新积仗,運(yùn)行效果如下:
DownloadImageService中的代碼:
public class DownloadImageService extends IntentService {
private static final String ACTION_DOWNLOAD_IMAGE="com.example.downloadimage.action.DOWNLOAD_IMAGE";
public static final String EXTRA_DOWNLOAD_IMAGE="com.example.downloadimage.extra.DOWNLOAD_IMAGE";
public DownloadImageService() {
super("DownloadImageService");
}
public static void startDownload(Context context,String path){
Intent intent=new Intent(context,DownloadImageService.class);
intent.setAction(ACTION_DOWNLOAD_IMAGE);
intent.putExtra(EXTRA_DOWNLOAD_IMAGE,path);
context.startService(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
if(intent!=null){
if(intent.getAction().equals(ACTION_DOWNLOAD_IMAGE)){
String path=intent.getStringExtra(EXTRA_DOWNLOAD_IMAGE);
handleDownloadTask(path);
}
}
}
private void handleDownloadTask(String path) {
//模擬耗時(shí)操作
try{
Thread.sleep(3*1000);
}catch(InterruptedException e){
e.printStackTrace();
}
//利用廣播通知主界面更新
Intent intent=new Intent(MainActivity.RESULT_DOWNLOAD_IMAGE);
intent.putExtra(EXTRA_DOWNLOAD_IMAGE,path);
sendBroadcast(intent);
}
@Override
public void onCreate(){
super.onCreate();
}
@Override
public void onDestroy(){
super.onDestroy();
}
}
MainActivity中的代碼:
public class MainActivity extends ActionBarActivity {
public static final String RESULT_DOWNLOAD_IMAGE="com.example.downloadimage.result.DOWNLOAD_IMAGE";
private Button addTaskBtn;
private LinearLayout layoutContainer;
private int i=0;
private BroadcastReceiver resultReceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
if(intent!=null){
if(intent.getAction().equals(RESULT_DOWNLOAD_IMAGE)){
String path=intent.getStringExtra(DownloadImageService.EXTRA_DOWNLOAD_IMAGE);
TextView tv=(TextView)layoutContainer.findViewWithTag(path);
tv.setText(path+" successfully downloaded");
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addTaskBtn=(Button)findViewById(R.id.addTaskBtn);
layoutContainer=(LinearLayout)findViewById(R.id.layoutContainer);
addTaskBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
String path="www.lemon.com/imgs/img"+(++i)+".png";
DownloadImageService.startDownload(MainActivity.this,path);
TextView tv=new TextView(MainActivity.this);
tv.setText(path+" is downloading");
tv.setTag(path);
layoutContainer.addView(tv);
}
});
registerReceiver(resultReceiver);
}
private void registerReceiver(BroadcastReceiver receiver) {
IntentFilter intentFilter=new IntentFilter(RESULT_DOWNLOAD_IMAGE);
registerReceiver(receiver,intentFilter);
}
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(resultReceiver);
}
}
主布局文件的代碼:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/layoutContainer"
tools:context="com.example.downloadimage.MainActivity" >
<Button
android:id="@+id/addTaskBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Download Task"
/>
</LinearLayout>
其實(shí),邏輯還是相當(dāng)簡(jiǎn)單的蜕猫,每當(dāng)點(diǎn)擊“Add Download Task”按鈕時(shí)寂曹,會(huì)去調(diào)用DownloadImageService的startDownload方法,在startDownload中,會(huì)調(diào)用startService方法去啟動(dòng)我們的DownloadImageService隆圆,startService方法的參數(shù)是一個(gè)intent,該intent中封裝了我們這回要執(zhí)行的任務(wù)類(lèi)型(action)以及執(zhí)行任務(wù)所需的參數(shù)(Extra),之后會(huì)執(zhí)行到onHandleIntent方法漱挚,此時(shí)的onHandleIntent方法是運(yùn)行在子線程中的,在onHandleIntent方法中渺氧,會(huì)去執(zhí)行圖片下載的具體任務(wù)旨涝,下載完成后,會(huì)發(fā)送一個(gè)廣播通知主界面相關(guān)任務(wù)記錄進(jìn)行更新侣背。
講到這里白华,大家對(duì)IntentService的基本用法應(yīng)該有一個(gè)大致的了解了吧,但是目前的理解層次還不能完全回答之前提出的三個(gè)問(wèn)題贩耐,看來(lái)弧腥,只能讓源碼君幫幫我們了_
IntentService的源碼如下:
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
}
IntentService中有兩個(gè)成員變量較為重要,一個(gè)是Looper類(lèi)型的mServiceLooper潮太,還有一個(gè)是ServiceHandler類(lèi)型的mServiceHandler管搪。這個(gè)ServiceHandler是個(gè)啥東東呢?我們看一下它的源碼铡买,ServiceHandler繼承自Handler更鲁,內(nèi)部提供了一個(gè)以Looper為參數(shù)的構(gòu)造函數(shù),也就是說(shuō)奇钞,如果我們傳入的Looper是子線程的Looper澡为,ServiceHandler的handleMessage方法就會(huì)運(yùn)行在子線程中。我們?cè)偃タ匆幌耂erviceHandler的handleMessage方法中有些什么蛇券,原來(lái)是依次調(diào)用了onHandleIntent缀壤,stopSelf方法,看到這里纠亚,對(duì)異步消息處理機(jī)制及HandlerThread掌握較牢固的朋友應(yīng)該都能猜到接下來(lái)的源碼了,不要激動(dòng)筋夏,咱們繼續(xù)往下看_
接下來(lái)看到IntentService的onCreate方法蒂胞,在onCreate中,先去創(chuàng)建并啟動(dòng)了HandlerThread条篷,然后用該HandlerThread的Looper去初始化我們的ServiceHandler骗随,這樣ServiceHandler就用的是子線程的Looper,其handleMessage方法自然是運(yùn)行在子線程中的赴叹,所以handleMessage中的onHandleIntent和stopSelf方法自然也是運(yùn)行在子線程中的鸿染。
當(dāng)我們調(diào)用startService方法啟動(dòng)服務(wù)時(shí),首先會(huì)去調(diào)用onStartCommand方法乞巧,在onStartCommand方法中涨椒,會(huì)再去調(diào)用onStart方法,并將intent和startId傳入,我們重點(diǎn)看一下onStart方法蚕冬。在onStart方法中免猾,會(huì)先去通過(guò)ServiceHandler對(duì)象去獲取一條消息,之后將消息的arg1字段設(shè)置為startId囤热,obj字段設(shè)置為intent猎提,最后用ServiceHandler對(duì)象將我們這條消息發(fā)送出去。
之后消息便會(huì)輾轉(zhuǎn)到handleMessage方法中了旁蔼,注意锨苏,此時(shí)handleMessage是運(yùn)行在子線程中的,在handleMessage方法中棺聊,會(huì)將消息的obj字段取出強(qiáng)轉(zhuǎn)為Intent并作為參數(shù)傳入onHandleIntent方法中伞租,之后將消息的arg1字段取出并作為參數(shù)傳入stopSelf中。
當(dāng)請(qǐng)求全部執(zhí)行完成后躺屁,會(huì)銷(xiāo)毀我們的Service肯夏。銷(xiāo)毀Service時(shí)會(huì)回調(diào)onDestroy方法,在onDestroy方法中會(huì)調(diào)用mServiceLooper.quit()來(lái)釋放我們的Looper犀暑。
好了驯击,到這里IntentService的源碼就基本分析完畢了,大家對(duì)IntentService的理解是不是又更上一層樓了呢_
參考:《第一行代碼 Android》
http://blog.csdn.net/lmj623565791/article/details/47143563