Android Service詳解

個人學習筆記,未經允許,不得轉載,謝謝~

本文目錄

一、簡介

官方定義:

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。

圖1

二、創(chuàng)建Service

2個步驟:

  1. 創(chuàng)建一個類繼承自Service(或它的子類),重寫里面的一些關鍵的回調方法,如onStartCommand(),onBind()等
  2. 在清單文件里面為其聲明,并根據需要配置一些屬性

在清單文件里進行聲明時,只有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()

  1. 生命周期及相關方法解析

    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_REDELIVERYSTART_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。

  2. 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;
        }
    }
}

運行截圖:

圖2
圖3

從log中可以看出,通過調用startService()啟動后Service的生命周期,以及在Service創(chuàng)建后多次調用startService()都會回調 onStartCommand()(如:圖3)。并且Service在啟動后,Service的生命周期不受其他組件的影響,即使啟動它的Activity已經銷毀了,Service也仍在運行(如:圖4)。

圖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也立即終止。

  1. 生命周期及相關方法解析

    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。

  1. demo:Activity與Service通信

    1. Step 1:在自定義的Service中繼承Binder,實現(xiàn)自己的Binder對象
    2. 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;
        }
    }
}

  1. 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");
        }
    };
}

運行截圖:

圖5
  • 再添加一個Acticity綁定該Service:
圖6
  • 從圖6日志中可以看出,當首次使用bindService()綁定Service時,系統(tǒng)會實例化一個Service實例,并調用其onCreate()和onBind()方法,此后如果再次使用bindService()綁定Service,系統(tǒng)不會創(chuàng)建新的Sevice實例,也不會再調用onBind()方法,只會直接把IBinder對象傳遞給其他后來增加的客戶端。

  • 當所有與Service綁定的組件都調用了unbindService()方法后,系統(tǒng)會銷毀Service:

圖7

五、IntentService

  1. 定義

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受其影響,所以可以考慮使用WorkManagerJobIntentService。

  1. 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

從圖8日志中可以看出,IntentService在執(zhí)行完任務后就會自行銷毀執(zhí)行onDestroy()。

  1. 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);
}

總結:

  1. 在 onCreate() 方法中,新建了一個 HandlerThread 對象(thread),并用HandlerThread創(chuàng)建的Looper創(chuàng)建了一個Handler對象(mServiceHanlder),使mServiceHanlder和thread的Looper相關聯(lián);
  2. 在 onStart() 方法中,將 Intent指定到Message,發(fā)送給 mServiceHandler,此Intent就是我們通過 startService(Intent) 傳入的 Intent。
  3. mServiceHanlder 接收到任務請求,調用 onHandleIntent() 方法處理任務請求,處理完所有請求后,調用 stopSelf() 銷毀IntentService。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

相關閱讀更多精彩內容

友情鏈接更多精彩內容