個人學習筆記,未經允許,不得轉載,謝謝~
本文目錄
- 一、簡介
- 二、創(chuàng)建Service
-
三、startService()
1. 生命周期及相關方法解析
2. demo -
四、bindService()
1. 生命周期及相關方法解析
2. demo:Activity與Service通信 -
五、IntentService
1. 定義
2. IntentService的使用
3. IntentService源碼分析
一、簡介
官方定義:
Service 是一種可在后臺執(zhí)行長時間運行操作而不提供界面的應用組件。Service可由其他應用組件啟動,而且即使用戶切換到其他應用,Service仍將在后臺繼續(xù)運行。此外,組件可通過綁定到服務與之進行交互,甚至是執(zhí)行進程間通信 (IPC)。例如,服務可在后臺處理網絡事務、播放音樂,執(zhí)行文件 I/O 或與內容提供程序進行交互。
兩種方式:
- startService()
- bindService()
| 創(chuàng)建service | 銷毀service | service與啟動它的組件之間的通信方式 | service的生命周期 | |
|---|---|---|---|---|
| startService() | 在其他組件調用 startService() 時創(chuàng)建,然后無限期運行 | 1. stopSelf() 來自行停止運行。2. 其他組件調用 stopService() 來停止此Service。Service停止后,系統(tǒng)會將其銷毀 | 應用組件與服務間的唯一通信模式便是使用 startService() 傳遞的 Intent,啟動service后該service就處于獨立運行狀態(tài) | 圖1左 |
| bindService() | 該服務在其他組件(客戶端)調用 bindService() 時創(chuàng)建(其他組件不包括BroadcastReceiver) | 所有與Service綁定的組件都被銷毀,或者它們都調用了unbindService()方法后,系統(tǒng)會銷毀Service | 在Service中實現(xiàn) onBind() 回調方法返回 IBinder,從而定義與Service進行通信的接口;在與Service綁定的組件中通過 ServiceConnection進行通信。 | 圖1右 |
備注:同一個Service可能有組件調用了startService()啟動它,又有組件調用bindService()與它綁定。當同一個Service與其他組件同時存在這兩種聯(lián)系時,必須既要所有組件取消綁定也要stopService() 或 stopSelf()才會停止Service。
二、創(chuàng)建Service
2個步驟:
- 創(chuàng)建一個類繼承自Service(或它的子類),重寫里面的一些關鍵的回調方法,如onStartCommand(),onBind()等
- 在清單文件里面為其聲明,并根據需要配置一些屬性
在清單文件里進行聲明時,只有android:name屬性是必需的。但是適當添加其它屬性可以讓開發(fā)進行地更加順利,所以了解一下注冊一個Service可以聲明哪些屬性也是很有必要的。
<service android:description="string resource"
android:directBootAware=["true" | "false"]
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:foregroundServiceType=["connectedDevice" | "dataSync" |
"location" | "mediaPlayback" | "mediaProjection" |
"phoneCall"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>
-
android:description向用戶描述Service的字符串。 -
android:directBootAware服務是否支持直接啟動,即其是否可以在用戶解鎖設備之前運行。默認false。 -
android:enabled系統(tǒng)是否可實例化Service。默認為true,表示可以。只有在 <application> 和 <service> 屬性都為“true”(因為它們都默認使用該值)時,系統(tǒng)才能啟用服務。 -
android:exported其他應用的組件是否能調用服務或與之交互 。如果為false,則只有與Service同一個應用或者相同user ID的應用可以開啟或綁定此Service。它的默認值取決于Service是否有Intent Filters。如果一個filter都沒有,就意味著只有指定了Service的準確的類名才能調用,也就是說這個Service只能應用內部使用——其他的應用不知道它的類名。這種情況下exported的默認值就為false。反之,只要有了一個filter,就意味著Service是考慮到外界使用的情況的,這時exported的默認值就為true。 -
android:foregroundServiceType闡明服務是滿足特定用例要求的前臺服務,可以將多個前臺服務類型分配給特定服務。 -
android:icon表示Service的icon -
android:isolatedProcess如果設置為true,這個Service將運行在一個從系統(tǒng)中其他部分分離出來的特殊進程中,只能通過Service API來與它進行通信。默認為false。 -
android:label可向用戶顯示的服務名稱。 -
android:name實現(xiàn)服務的 Service 子類的名稱。此名稱應為完全限定類名稱(例如“com.example.project.RoomService”)。沒有默認值。必須指定。 -
android:permission其他組件必須具有所填的權限才能啟動這個Service。 -
android:processService運行的進程的name。正常情況下,應用的所有組件都會在為應用創(chuàng)建的默認進程中運行。該名稱與應用軟件包的名稱相同。
三、startService()
-
生命周期及相關方法解析
a.
startService(Intent intent)其它組件調用來啟動service- 參數(shù):Intent-需要包含具體啟動的service的完整類名
- 當調用startService()后:Service首次啟動,則先調用onCreate(),再調用onStartCommand();Service已經啟動,則直接調用onStartCommand()
b.
onCreate()當Service第一次被創(chuàng)建后立即回調該方法,該方法在整個生命周期 中只會調用一次!
c.onDestory()當Service停止后會回調該方法,該方法只會回調一次!
d.public int onStartCommand (Intent intent,int flags,int startId)- 當客戶端調用startService(Intent)方法時會回調,可多次調用startService()方法, 但不會再創(chuàng)建新的Service對象,而是繼續(xù)復用前面產生的Service對象,但會繼續(xù)回調 onStartCommand()方法!
- onStartCommand參數(shù):
參數(shù) 含義 Intent intent 在其他組件調用startService()方法啟動Service時,傳遞的一個Intent參數(shù),然后Service將會在onStartCommand()中接收這個Intent int flags 表示啟動請求時是否有額外數(shù)據,可選值: 0,START_FLAG_REDELIVERY,START_FLAG_RETRY。0:在正常創(chuàng)建Service的情況下,onStartCommand傳入的flags為0。START_FLAG_REDELIVERY:如果onStartCommand()方法的返回值是START_REDELIVER_INTENT,并且Service被系統(tǒng)kill后,則會重新創(chuàng)建Service,并且調用onStartCommand()時,會重傳intent,而傳入的flags就是START_FLAG_REDELIVERY。START_FLAG_RETRYService創(chuàng)建時,onStartCommand()方法未被調用或者沒有正常返回的異常情況下, 再次嘗試創(chuàng)建,傳入的flags就為START_FLAG_RETRY。int startId startId 用來代表這個唯一的啟動請求。可以在stopSelfResult(int startId)中傳入這個startId,用來終止Service。 - onStartCommand返回值:
返回值 含義 START_STICKY 當Service被系統(tǒng)kill后,系統(tǒng)將會嘗試重新創(chuàng)建此Service,一旦創(chuàng)建成功后將回調onStartCommand方法,但Intent將是null,除非有掛起的Intent,如PendingIntent。這個狀態(tài)下比較適用于不執(zhí)行命令、但無限期運行并等待作業(yè)的媒體播放器或類似服務。 START_NOT_STICKY 當Service因內存不足而被系統(tǒng)kill后,即使系統(tǒng)內存再次空閑時,系統(tǒng)也不會嘗試重新創(chuàng)建此Service。除非再次調用startService啟動此Service。 START_REDELIVER_INTENT 當Service被系統(tǒng)kill后,系統(tǒng)會自動重啟該服務,并重傳最后一個 Intent。適用于主動執(zhí)行應該立即恢復的作業(yè)(例如下載文件)的服務。 START_STICKY_COMPATIBILITY START_STICKY的兼容版本,不能保證Service被kill后會重啟 e.
stopSelf()自行停止Service運行(自殺式)。
f.stopSelfResult(int startId)只有startId和最后一次啟動請求相匹配,Service才會被停止。比如:我們想終止Service的時候又來了個啟動請求,這時候是不應該終止的,而我們還沒拿到最新請求的startId,如果用stopService的話就直接終止了,而用stopSelfResult方法就會及時避免終止。
g.stopService(Intent service)其它組件調用來停止Service運行(他殺式)。無論啟動了多少次Service,只需調用一次StopService即可停掉Service。 -
demo
a. 自定義Service,重寫相關方法:
public class DemoStartService extends Service {
private static final String TAG = DemoStartService.class.getSimpleName();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i(TAG, "onBind");
return null;
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
}
b. 在清單文件中注冊:
<service
android:name=".DemoStartService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.wanda.servicedemo.action.START_SERVICE"/>
</intent-filter>
</service>
c. 在其他組件(這里是Activity)中調用startService( )和stopService( )
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
private Button mStartServiceButton;
private Button mStopServiceButton;
private Intent mIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntent=new Intent(this,DemoStartService.class);
initViews();
mStartServiceButton.setOnClickListener(this);
mStopServiceButton.setOnClickListener(this);
}
private void initViews(){
mStartServiceButton=findViewById(R.id.startService);
mStopServiceButton=findViewById(R.id.stopService);
}
//點擊按鈕進行startService和stopService操作
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.startService:
Log.i(TAG, "onClick: startService");
startService(mIntent);
break;
case R.id.stopService:
Log.i(TAG, "onClick: stopService");
stopService(mIntent);
break;
}
}
}
運行截圖:
從log中可以看出,通過調用startService()啟動后Service的生命周期,以及在Service創(chuàng)建后多次調用startService()都會回調 onStartCommand()(如:圖3)。并且Service在啟動后,Service的生命周期不受其他組件的影響,即使啟動它的Activity已經銷毀了,Service也仍在運行(如:圖4)。
四、bindService()
應用組件通過調用 bindService() 與Service綁定,從而創(chuàng)建長期連接。如需與其他組件進行交互,或需要進程間通信 (IPC) ,則應通過bindService()創(chuàng)建綁定服務。
當首次使用bindService()綁定Service時,系統(tǒng)會實例化一個Service實例,并調用其onCreate()和onBind()方法,然后調用者就可以通過IBinder和Service進行交互了,此后如果再次使用bindService綁定Service,系統(tǒng)不會創(chuàng)建新的Sevice實例,也不會再調用onBind()方法,只會直接把IBinder對象傳遞給其他后來增加的客戶端。(下文demo中有驗證)
如果要解除與Service的綁定,只需調用unbindService(),此時onUnbind()和onDestory()將會被調用。假如有多個客戶端綁定同一個Service,當所有的客戶端都和service解除綁定后,系統(tǒng)會銷毀Service。(除非Service也被startService()方法開啟)
bindService模式下的Service是與調用者相互關聯(lián)的,在bindService后,一旦調用者銷毀,那么Service也立即終止。
-
生命周期及相關方法解析
a.
boolean bindService(Intent service, ServiceConnection conn, int flags)
注:BroadcastReceiver不能調用該方法。但是可以在已經動態(tài)注冊的BroadcastReceiver中調用此方法,因為此BroadcastReceiver的壽命捆綁在另一個對象上(注冊它的對象)。- 參數(shù)
參數(shù) 含義 Intent service 明確標識需要連接的服務 ServiceConnection conn 一個ServiceConnection對象,用來監(jiān)聽訪問者與Service間的連接情況。 連接成功回調該對象中的onServiceConnected (ComponentName name, IBinder service)方法;連接丟失則回調onServiceDisconnected (ComponentName name)方法,通常發(fā)生在Service所在的進程由于異常終止或者其他原因終止,導致Service與訪問者間斷開連接時,主動通過unBindService() 方法斷開并不會調用上述方法!
onServiceConnected (ComponentName name, IBinder service):
- ComponentName name:已連接的Service的具體組件名稱
- IBinder service:IBinder對象,實現(xiàn)與Service之間的通信。Service的onBind()方法返回的IBinder對象會傳遞到此參數(shù),我們就可以通過這個IBinder對象與Service進行通信。
onServiceDisconnected(ComponentName name):
- ComponentName name:連接丟失的Service的具體組件名稱。int flags 綁定時的選項。
可能是 0,[BIND_AUTO_CREATE],[BIND_DEBUG_UNBIND],[BIND_NOT_FOREGROUND],[BIND_ABOVE_CLIENT],[BIND_ALLOW_OOM_MANAGEMENT],[BIND_WAIVE_PRIORITY],[BIND_IMPORTANT],[BIND_ADJUST_WITH_ACTIVITY],[BIND_NOT_PERCEPTIBLE],[BIND_INCLUDE_CAPABILITIES]
以下各個flag的含義稍作了解:
·BIND_AUTO_CREATE:若綁定服務時服務未啟動,則會自動啟動服務。 注意,這種情況下服務的onStartCommand仍然未被調用(它只會在顯式調用startService時才會被調用)。
· BIND_DEBUG_UNBIND:使用此標志綁定服務之后的unBindService方法會無效。 這種方法會引起內存泄露,只能在調試時使用。
· BIND_NOT_FOREGROUND:被綁定的服務進程優(yōu)先級不允許被提到FOREGROUND級別。
· BIND_ABOVE_CLIENT:Service 進程比client本身的進程還重要,如果當綁定服務期間遇到OOM需要殺死進程,client進程會先于服務進程被殺死。
· BIND_ALLOW_OOM_MANAGEMENT:允許內存管理系統(tǒng)管理 Service 的進程,在內存不足時可以被kill。
· BIND_WAIVE_PRIORITY:不影響 Service 進程的優(yōu)先級的情況下,允許 Service 進程被加入后臺隊列中。
· BIND_IMPORTANT:被綁定的服務進程優(yōu)先級會被提到FOREGROUND級別。
· BIND_ADJUST_WITH_ACTIVITY:如果從一個 Activity 綁定,則這個 Service 進程的優(yōu)先級和 Activity 是否對用戶可見有關。- 返回值
返回值 含義 boolean · true:系統(tǒng)正在啟動你的client有權綁定的Service。
· false:如果系統(tǒng)不能找到Service或者你的client沒有權限去綁定該Service。
如果這個值是true,則稍后應調用unbindService(ServiceConnection)以釋放連接- 拋出
拋出 含義 SecurityException 如果調用方沒有訪問該Service的權限或找不到該Service。 b.
unbindService (ServiceConnection conn)參數(shù) 含義 ServiceConnection conn 之前提供給bindService()的ServiceConnection,值不能為空 c.
IBinder onBind (Intent intent)當其他組件想通過bindService()綁定Service時,系統(tǒng)會回調這個方法。在自定義的Service中重寫該方法時,需要返回一個IBinder對象,供客戶端與服務進行通信,但如果Service不允許綁定,則可以返回null。
- 參數(shù)
參數(shù) 含義 Intent intent 調用bindService()時傳入的用來綁定該Service的Intent,這里不會看到Intent中包含的其它內容 - 返回值
返回值 含義 IBinder 可當客戶端與Service連接成功后,客戶端通過該IBinder對象與Service進行通信 d.
boolean onUnbind (Intent intent)默認實現(xiàn)不執(zhí)行任何操作,并返回false。
-
參數(shù)
參數(shù) 含義 Intent intent 調用bindService()時傳入的用來綁定該Service的Intent -
返回值
參數(shù) 含義 boolean true:表示希望客戶端下一次綁定時能夠調用onRebind() e.
onRebind (Intent intent)服務未被銷毀,再次綁定時回調。前提是 onUnbind() 方法返回true。
-
demo:Activity與Service通信
- Step 1:在自定義的Service中繼承Binder,實現(xiàn)自己的Binder對象
- Step 2:通過onBind()方法返回自己的Binder對象
public class DemoStartService extends Service {
private static final String TAG = DemoStartService.class.getSimpleName();
private int mCount;
private boolean mQuit;
private MyBinder mBinder = new MyBinder();
public DemoStartService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i(TAG, "onBind");
return mBinder;
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
new Thread() {
public void run() {
while (!mQuit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mCount++;
}
}
}.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
public class MyBinder extends Binder {
public int getCount() {
return mCount;
}
}
}
- Step 3:在綁定該Service的類中定義一個ServiceConnection對象,重寫兩個方法:onServiceConnected()和onServiceDisconnected(),然后直接讀取傳遞過來的IBinder參數(shù)即可。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
private Button mStartServiceButton;
private Button mStopServiceButton;
private Button mBindServiceButton;
private Button mUnbindServiceButton;
private Button mGetAccountButton;
private Intent mIntent;
private DemoStartService.MyBinder mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate");
mIntent = new Intent(this, DemoStartService.class);
initViews();
}
private void initViews() {
mStartServiceButton = findViewById(R.id.startService);
mStopServiceButton = findViewById(R.id.stopService);
mBindServiceButton = findViewById(R.id.bindService);
mUnbindServiceButton = findViewById(R.id.unbindService);
mGetAccountButton = findViewById(R.id.getAccount);
mStartServiceButton.setOnClickListener(this);
mStopServiceButton.setOnClickListener(this);
mBindServiceButton.setOnClickListener(this);
mUnbindServiceButton.setOnClickListener(this);
mGetAccountButton.setOnClickListener(this);
}
//點擊按鈕進行startService和stopService操作
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.startService:
Log.i(TAG, "onClick: startService");
startService(mIntent);
break;
case R.id.stopService:
Log.i(TAG, "onClick: stopService");
stopService(mIntent);
break;
case R.id.bindService:
Log.i(TAG, "onClick: bindService");
bindService(mIntent, mConn, BIND_AUTO_CREATE);
break;
case R.id.unbindService:
Log.i(TAG, "onClick: unbindService");
unbindService(mConn);
break;
case R.id.getAccount:
Log.i(TAG, "onClick: count = " + mBinder.getCount());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
}
private ServiceConnection mConn = new ServiceConnection() {
//Activity與Service連接成功時回調該方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected");
mBinder = (DemoStartService.MyBinder) service;
}
//Activity與Service斷開連接時回調該方法
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected");
}
};
}
運行截圖:
- 再添加一個Acticity綁定該Service:
從圖6日志中可以看出,當首次使用bindService()綁定Service時,系統(tǒng)會實例化一個Service實例,并調用其onCreate()和onBind()方法,此后如果再次使用bindService()綁定Service,系統(tǒng)不會創(chuàng)建新的Sevice實例,也不會再調用onBind()方法,只會直接把IBinder對象傳遞給其他后來增加的客戶端。
當所有與Service綁定的組件都調用了unbindService()方法后,系統(tǒng)會銷毀Service:
五、IntentService
-
定義
IntentService 是Service的子類,用于處理后臺異步請求任務。由于Service在主線程,不能進行耗時操作,因此Google提供了IntentService,內部維護了一個子線程來進行操作。用戶通過調用 Context.startService(Intent) 發(fā)送請求,Service根據請求啟動,在IntentService內維護了一個工作線程來處理耗時操作,當任務執(zhí)行完后,IntentService會自動停止。
所有的請求都在同一個工作線程上處理,一次處理一個請求,所以處理完所有的請求可能會花費很長的時間,但由于 IntentService 是另外創(chuàng)建子線程來工作,所以不會阻礙主線程,防止出現(xiàn)ANR。
使用場景:可以用來處理后臺長時間的耗時操作,如:文件下載、音樂播放。
IntentService已經在Android API 30棄用(對應Android 11):在Android 8.0增加了Background execution limits,而IntentService受其影響,所以可以考慮使用WorkManager或JobIntentService。
-
IntentService的使用
以下demo通過IntentService實現(xiàn)在后臺循環(huán)播放音樂。
2個步驟
setp1
創(chuàng)建IntentService的子類,實現(xiàn)onHandleIntent()等方法,并在清單文件中注冊
//創(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此任務的出當前線程名
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();
}
}
并在清單文件中注冊:
<service
android:name=".MusicPlayerService"
android:exported="false"></service>
setp2
在 Activity 中通過調用 startService(Intent) 方法發(fā)送任務請求
//在Activity添加Button啟動IntentService(僅展示部分代碼)
case R.id.startIntentService:
Log.i(TAG, "onClick: startIntentService");
MusicPlayerService.startPlayer(this);
break;
從圖8日志中可以看出,IntentService在執(zhí)行完任務后就會自行銷毀執(zhí)行onDestroy()。
-
IntentService源碼分析
雖然IntentService已經在Android API 30棄用,但是我們還是需要學習其原理。在分析IntentService源碼前,需要提前學習Handler相關知識,這可以使我們對IntentService理解得更透徹。如果你已經學習過了Handler,那接下來可以跟我一起分析源碼啦。
先看看IntentService類import了什么:
import android.annotation.Nullable;
//WorkerThread注解:表示只能在WorkThread上調用被該注解標記的方法,也就是標記@WorkThread的方法只能在子線程上運行。如果被該注解標記的元素是一個類,那么類中的所有方法都應該在WorkThread上調用。
import android.annotation.WorkerThread;
//UnsupportedAppUsage注解:簡單理解為不支持外部應用使用被此注釋聲明的變量或方法等。
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
//引入Hnadler說明在IntentService內部的工作方式和Handler息息相關
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
接下來看看IntentService是怎么具體實現(xiàn)的吧:
//注解Deprecated表示IntentService被棄用。實際上IntentService在Android API 30(Android 11)被棄用,因為IntentService受Android 8.0推出的后臺執(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)建了一個內部類,繼承自Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//處理我們重寫的該方
onHandleIntent((Intent)msg.obj)
//當執(zhí)行完任務后,Service就銷毀
stopSelf(msg.arg1);
}
}
/**
* 構造函數(shù)
*
* @param name 用于命名所在的工作線程名稱
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* 設置Intent是否重傳,通常在構造函數(shù)中調用。
*
* 當enabled為true,onStartCommand(Intent,int,int)將返回START_REDELIVER_ INTENT,
* 且如果在onHandleIntent(Intent)返回前,進程就終止了,則進程將重啟并重傳intent。
* 當enabled為false(默認),onStartCommand(Intent,int,int)將返回START_NOT_STICKY,
* 如果進程終止,Intent也隨之終止。
*
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//HandlerThread就是一個帶有Handler的Thread,這里就是創(chuàng)建了一個線程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//獲取這個線程的Looper
mServiceLooper = thread.getLooper();
//創(chuàng)建了一個Handler,并給Handler指定了thread的looper,說明此Handler將執(zhí)行此子線程上的任務
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//將關于Intent的消息發(fā)送到隊列中給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);
}
總結:
- 在 onCreate() 方法中,新建了一個 HandlerThread 對象(thread),并用HandlerThread創(chuàng)建的Looper創(chuàng)建了一個Handler對象(mServiceHanlder),使mServiceHanlder和thread的Looper相關聯(lián);
- 在 onStart() 方法中,將 Intent指定到Message,發(fā)送給 mServiceHandler,此Intent就是我們通過 startService(Intent) 傳入的 Intent。
- mServiceHanlder 接收到任務請求,調用 onHandleIntent() 方法處理任務請求,處理完所有請求后,調用 stopSelf() 銷毀IntentService。