個(gè)人學(xué)習(xí)筆記关翎,未經(jīng)允許,不得轉(zhuǎn)載沐祷,謝謝~
一嚷闭、定義
IntentService 是Service的子類,用于處理后臺(tái)異步請(qǐng)求任務(wù)戈轿。由于Service在主線程凌受,不能進(jìn)行耗時(shí)操作,因此Google提供了IntentService思杯,內(nèi)部維護(hù)了一個(gè)子線程來進(jìn)行操作胜蛉。用戶通過調(diào)用 Context.startService(Intent) 發(fā)送請(qǐng)求挠进,Service根據(jù)請(qǐng)求啟動(dòng),在IntentService內(nèi)維護(hù)了一個(gè)工作線程來處理耗時(shí)操作誊册,當(dāng)任務(wù)執(zhí)行完后领突,IntentService會(huì)自動(dòng)停止。
所有的請(qǐng)求都在同一個(gè)工作線程上處理案怯,一次處理一個(gè)請(qǐng)求君旦,所以處理完所有的請(qǐng)求可能會(huì)花費(fèi)很長的時(shí)間,但由于 IntentService 是另外創(chuàng)建子線程來工作嘲碱,所以不會(huì)阻礙主線程金砍,防止出現(xiàn)ANR。
使用場(chǎng)景:可以用來處理后臺(tái)長時(shí)間的耗時(shí)操作麦锯,如:文件下載恕稠、音樂播放。
IntentService已經(jīng)在Android API 30棄用(對(duì)應(yīng)Android 11):在Android 8.0增加了Background execution limits扶欣,而IntentService受其影響鹅巍,所以可以考慮使用WorkManager或JobIntentService。
二料祠、IntentService的使用
以下demo通過IntentService實(shí)現(xiàn)在后臺(tái)循環(huán)播放音樂骆捧。
2個(gè)步驟
setp1
創(chuàng)建IntentService的子類,實(shí)現(xiàn)onHandleIntent()等方法髓绽,并在清單文件中注冊(cè)
//創(chuàng)建IntentService的子類
public class MusicPlayerService extends IntentService {
private static final String ACTION_PLAY_MUSIC = "com.wanda.servicedemo.action.PLAY_MUSIC";
private static final String TAG = MusicPlayerService.class.getSimpleName();
private MediaPlayer mMediaPlayer;
public MusicPlayerService() {
super("MusicPlayerService");
}
public static void startPlayer(Context context) {
Log.i(TAG, "startPlayer");
Intent intent = new Intent(context, MusicPlayerService.class);
intent.setAction(ACTION_PLAY_MUSIC);
context.startService(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
Log.i(TAG, "onHandleIntent: action = " + action);
if (ACTION_PLAY_MUSIC.equals(action)) {
handleActionPlayMusic();
}
}
}
private void handleActionPlayMusic() {
boolean isMainThread = Looper.getMainLooper().getThread() == Thread.currentThread();
//打印handle此任務(wù)的出當(dāng)前線程名
Log.i(TAG, "handleActionPlayMusic: Current Thread is " +
Thread.currentThread().getName() +
" , is MainThread: " + isMainThread);
if (mMediaPlayer == null) {
mMediaPlayer = MediaPlayer.create(this, R.raw.record);
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
}
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Log.i(TAG, "onStart");
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
}
并在清單文件中注冊(cè):
<service
android:name=".MusicPlayerService"
android:exported="false"></service>
setp2
在 Activity 中通過調(diào)用 startService(Intent) 方法發(fā)送任務(wù)請(qǐng)求
//在Activity添加Button啟動(dòng)IntentService(僅展示部分代碼)
case R.id.startIntentService:
Log.i(TAG, "onClick: startIntentService");
MusicPlayerService.startPlayer(this);
break;
從圖8日志中可以看出敛苇,IntentService在執(zhí)行完任務(wù)后就會(huì)自行銷毀執(zhí)行onDestroy()。
三梧宫、IntentService源碼分析
雖然IntentService已經(jīng)在Android API 30棄用接谨,但是我們還是需要學(xué)習(xí)其原理。在分析IntentService源碼前塘匣,需要提前學(xué)習(xí)Handler相關(guān)知識(shí),這可以使我們對(duì)IntentService理解得更透徹巷帝。如果你已經(jīng)學(xué)習(xí)過了Handler忌卤,那接下來可以跟我一起分析源碼啦。
先看看IntentService類import了什么:
import android.annotation.Nullable;
//WorkerThread注解:表示只能在WorkThread上調(diào)用被該注解標(biāo)記的方法楞泼,也就是標(biāo)記@WorkThread的方法只能在子線程上運(yùn)行驰徊。如果被該注解標(biāo)記的元素是一個(gè)類,那么類中的所有方法都應(yīng)該在WorkThread上調(diào)用堕阔。
import android.annotation.WorkerThread;
//UnsupportedAppUsage注解:簡單理解為不支持外部應(yīng)用使用被此注釋聲明的變量或方法等棍厂。
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
//引入Hnadler說明在IntentService內(nèi)部的工作方式和Handler息息相關(guān)
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
接下來看看IntentService是怎么具體實(shí)現(xiàn)的吧:
//注解Deprecated表示IntentService被棄用。實(shí)際上IntentService在Android API 30(Android 11)被棄用超陆,因?yàn)镮ntentService受Android 8.0推出的后臺(tái)執(zhí)行限制所影響牺弹。
@Deprecated
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//創(chuàng)建了一個(gè)內(nèi)部類浦马,繼承自Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//處理我們重寫的該方
onHandleIntent((Intent)msg.obj)
//當(dāng)執(zhí)行完任務(wù)后,Service就銷毀
stopSelf(msg.arg1);
}
}
/**
* 構(gòu)造函數(shù)
*
* @param name 用于命名所在的工作線程名稱
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* 設(shè)置Intent是否重傳张漂,通常在構(gòu)造函數(shù)中調(diào)用晶默。
*
* 當(dāng)enabled為true,onStartCommand(Intent,int,int)將返回START_REDELIVER_ INTENT航攒,
* 且如果在onHandleIntent(Intent)返回前磺陡,進(jìn)程就終止了,則進(jìn)程將重啟并重傳intent漠畜。
* 當(dāng)enabled為false(默認(rèn))币他,onStartCommand(Intent,int,int)將返回START_NOT_STICKY,
* 如果進(jìn)程終止憔狞,Intent也隨之終止圆丹。
*
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//HandlerThread就是一個(gè)帶有Handler的Thread,這里就是創(chuàng)建了一個(gè)線程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//獲取這個(gè)線程的Looper
mServiceLooper = thread.getLooper();
//創(chuàng)建了一個(gè)Handler躯喇,并給Handler指定了thread的looper辫封,說明此Handler將執(zhí)行此子線程上的任務(wù)
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//將關(guān)于Intent的消息發(fā)送到隊(duì)列中給Handler處理
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
//IntentService中不需要重寫該方法
@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();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
總結(jié):
- 在 onCreate() 方法中,新建了一個(gè) HandlerThread 對(duì)象(thread)廉丽,并用HandlerThread創(chuàng)建的Looper創(chuàng)建了一個(gè)Handler對(duì)象(mServiceHanlder)倦微,使mServiceHanlder和thread的Looper相關(guān)聯(lián);
- 在 onStart() 方法中正压,將 Intent指定到Message欣福,發(fā)送給 mServiceHandler,此Intent就是我們通過 startService(Intent) 傳入的 Intent焦履。
- mServiceHanlder 接收到任務(wù)請(qǐng)求拓劝,調(diào)用 onHandleIntent() 方法處理任務(wù)請(qǐng)求,處理完所有請(qǐng)求后嘉裤,調(diào)用 stopSelf() 銷毀IntentService郑临。