23 個(gè)重難點(diǎn)突破,帶你吃透 Service 知識(shí)點(diǎn)「長達(dá) 1W+ 字」

前言

  • 學(xué) Android 有一段時(shí)間了,想必不少人也和我一樣,平時(shí)經(jīng)常東學(xué)西湊,感覺知識(shí)點(diǎn)有些凌亂難成體系。所以趁著這幾天忙里偷閑,把學(xué)的東西歸納下,捋捋思路。

這篇文章主要針對 Service 相關(guān)的知識(shí)點(diǎn),進(jìn)行詳細(xì)的梳理,祝大家食用愉快!

文章目錄

文章目錄

方便大家學(xué)習(xí),我在 GitHub 建立了 倉庫


第一篇:Service 是什么


Service 是什么

1.1 什么是 Service

什么是 Service
  • Service (服務(wù)) 是一個(gè)一種可以在后臺(tái)執(zhí)行長時(shí)間運(yùn)行操作而沒有用戶界面的應(yīng)用組件。
  • 服務(wù)可由其他應(yīng)用組件啟動(dòng)(如 Activity ),服務(wù)一旦被啟動(dòng)將在后臺(tái)一直運(yùn)行,即使啟動(dòng)服務(wù)的組件( Activity )已銷毀也不受影響。
  • 此外,組件可以綁定到服務(wù),以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 ( IPC )。

1.2 Service 通??偸欠Q之為 “后臺(tái)服務(wù)”

Service 通??偸欠Q之為 “后臺(tái)服務(wù)”
  • 其中 “后臺(tái)” 一詞是相對于前臺(tái)而言的,具體是指:其本身的運(yùn)行并不依賴于用戶可視的 UI 界面
  • 因此,從實(shí)際業(yè)務(wù)需求上來理解,Service 的適用場景應(yīng)該具備以下條件:
  1. 并不依賴于用戶可視的 UI 界面(當(dāng)然,這一條其實(shí)也不是絕對的,如前臺(tái) Service 就是與 Notification 界面結(jié)合使用的)

  2. 具有較長時(shí)間的運(yùn)行特性

  3. 注意: 是運(yùn)行在主線程當(dāng)中的

1.3 服務(wù)進(jìn)程

服務(wù)進(jìn)程
  • 服務(wù)進(jìn)程是通過 startService() 方法啟動(dòng)的進(jìn)程,但不屬于前臺(tái)進(jìn)程和可見進(jìn)程。例如,在后臺(tái)播放音樂或者在后臺(tái)下載就是服務(wù)進(jìn)程。

  • 系統(tǒng)保持它們運(yùn)行,除非沒有足夠內(nèi)存來保證所有的前臺(tái)進(jìn)程和可視進(jìn)程。

第二篇:生命周期


生命周期

2.1 Service 的生命周期

  • 我們先來看看 Service 的生命周期 的基本流程
  • 一張聞名遐邇的圖


    Service的生命周期

2.2 開啟 Service 的兩種方式

開啟 Service 的兩種方式

2.2.1 startService()

startService()
  1. 定義一個(gè)類繼承 Service

  2. Manifest.xml 文件中配置該 Service

  3. 使用 ContextstartService(intent) 方法開啟服務(wù)。

  4. 使用 ContextstopService(intent) 方法關(guān)閉服務(wù)。

  5. 該啟動(dòng)方式,app 殺死、Activity 銷毀沒有任何影響,服務(wù)不會(huì)停止銷毀。

2.2.2 bindService()

bindService()
  1. 創(chuàng)建 BindService 服務(wù)端,繼承 Service 并在類中,創(chuàng)建一個(gè)實(shí)現(xiàn) IBinder 接口的實(shí)例對象,并提供公共方法給客戶端( Activity )調(diào)用。

  2. onBinder() 回調(diào)方法返回該 Binder 實(shí)例。

  3. 在客戶端( Activity )中, 從 onServiceConnection() 回調(diào)方法參數(shù)中接收 Binder ,通過 Binder 對象即可訪問 Service 內(nèi)部的數(shù)據(jù)。

  4. manifests 中注冊 BindService , 在客戶端中調(diào)用 bindService() 方法開啟綁定 Service , 調(diào)用 unbindService() 方法注銷解綁 Service 。

  5. 該啟動(dòng)方式依賴于客戶端生命周期,當(dāng)客戶端 Activity 銷毀時(shí), 沒有調(diào)用 unbindService() 方法 , Service 也會(huì)停止銷毀。

2.3 Service 有哪些啟動(dòng)方法,有什么區(qū)別,怎樣停用 Service

Service 的啟動(dòng)與綁定
  • Service 的生命周期中,被回調(diào)的方法比 Activity 少一些,只有 onCreate , onStartCommand , onDestroy , onBindonUnbind 。
  • 通常有兩種方式啟動(dòng)一個(gè) Service , 他們對 Service 生命周期的影響是不一樣的。

2.3.1 通過 startService

被啟動(dòng)的服務(wù)的生命周期
  • Service 會(huì)經(jīng)歷 onCreateonStartCommand ,然后處于運(yùn)行狀態(tài),stopService 的時(shí)候調(diào)用 onDestroy
    方法。

如果是調(diào)用者自己直接退出而沒有調(diào)用 stopService 的話,Service 會(huì)一直在后臺(tái)運(yùn)行。

2.3.2 通過 bindService

被綁定的服務(wù)的生命周期

Service 會(huì)運(yùn)行 onCreate ,然后是調(diào)用 onBind , 這個(gè)時(shí)候調(diào)用者和 Service 綁定在一起。調(diào)用者退出了,Srevice 就會(huì)調(diào)用 onUnbind -> onDestroyed 方法。

所謂綁定在一起就共存亡了。調(diào)用者也可以通過調(diào)用 unbindService 方法來停止服務(wù),這時(shí)候 Srevice 就會(huì)調(diào)用 onUnbind -> onDestroyed 方法。

2.3.3 需要注意的是如果這幾個(gè)方法交織在一起的話,會(huì)出現(xiàn)什么情況呢?

被啟動(dòng)又被綁定的服務(wù)的生命周期
  1. 一個(gè)原則是 ServiceonCreate 的方法只會(huì)被調(diào)用一次,就是你無論多少次的 startServicebindServiceService 只被創(chuàng)建一次。

  2. 如果先是 bind 了,那么 start 的時(shí)候就直接運(yùn)行 ServiceonStartCommand 方法,如果先是 start ,那么 bind 的時(shí)候就直接運(yùn)行 onBind 方法。

  3. 如果 service 運(yùn)行期間調(diào)用了 bindService ,這時(shí)候再調(diào)用 stopService 的話,service 是不會(huì)調(diào)用 onDestroy 方法的,servicestop 不掉了,只能調(diào)用 UnbindService , service 就會(huì)被銷毀

  4. 如果一個(gè) service 通過 startServicestart 之后,多次調(diào)用 startService 的話,service 會(huì)多次調(diào)
    onStartCommand 方法。多次調(diào)用 stopService 的話,service 只會(huì)調(diào)用一次 onDestroyed 方法。

  5. 如果一個(gè) service 通過 bindServicestart 之后,多次調(diào)用 bindService 的話,service 只會(huì)調(diào)用一次 onBind 方法。多次調(diào)用 unbindService 的話會(huì)拋出異常。

第三篇:Service 與 Thread


Service 與 Thread

3.1 Service 和 Thread 的區(qū)別

Service 和 Thread 的區(qū)別

3.1.1 首先第一點(diǎn)定義上

定義上
  1. thread 是程序執(zhí)行的最小單元,他是分配 cpu 的基本單位安卓系統(tǒng)中,我們常說的主線程,UI 線程,也是線程的一種。當(dāng)然,線程里面還可以執(zhí)行一些耗時(shí)的異步操作。
  2. service 大家記住,它是安卓中的一種特殊機(jī)制,service 是運(yùn)行在主線程當(dāng)中的,所以說它不能做耗時(shí)操作,它是由系統(tǒng)進(jìn)程托管,其實(shí) service 也是一種輕量級的 IPC 通信,因?yàn)?activity 可以和 service 綁定,可以和 service 進(jìn)行數(shù)據(jù)通信。
  3. 而且有一種情況,activityservice 是處于不同的進(jìn)程當(dāng)中,所以說它們之間的數(shù)據(jù)通信,要通過 IPC 進(jìn)程間通信的機(jī)制來進(jìn)行操作。

3.1.2 第二點(diǎn)是在實(shí)際開發(fā)的過程當(dāng)中

第二點(diǎn)是在實(shí)際開發(fā)的過程當(dāng)中
  1. 在安卓系統(tǒng)當(dāng)中,線程一般指的是工作線程,就是后臺(tái)線程,做一些耗時(shí)操作的線程,而主線程是一種特殊的線程,它只是負(fù)責(zé)處理一些 UI 線程的繪制,UI 線程里面絕對不能做耗時(shí)操作,這里是最基本最重要的一點(diǎn)。(這是 Thread 在實(shí)際開發(fā)過程當(dāng)中的應(yīng)用)
  2. service 是安卓當(dāng)中,四大組件之一,一般情況下也是運(yùn)行在主線程當(dāng)中,因此 service 也是不可以做耗時(shí)操作的,否則系統(tǒng)會(huì)報(bào) ANR 異常( ANR 全稱:Application Not Responding ),就是程序無法做出響應(yīng)。
  3. 如果一定要在 service 里面進(jìn)行耗時(shí)操作,一定要記得開啟單獨(dú)的線程去做。

3.1.3 第三點(diǎn)是應(yīng)用場景上

應(yīng)用場景上
  1. 當(dāng)你需要執(zhí)行耗時(shí)的網(wǎng)絡(luò),或者這種文件數(shù)據(jù)的查詢,以及其它阻塞 UI 線程的時(shí)候,都應(yīng)該使用工作線程,也就是開啟一個(gè)子線程的方式。
  2. 這樣才能保證 UI 線程不被占用,而影響用戶體驗(yàn)。
  3. service 來說,我們經(jīng)常需要長時(shí)間在后臺(tái)運(yùn)行,而且不需要進(jìn)行交互的情況下才會(huì)使用到服務(wù),比如說,我們在后臺(tái)播放音樂,開啟天氣預(yù)報(bào)的統(tǒng)計(jì),還有一些數(shù)據(jù)的統(tǒng)計(jì)等等。

3.2 為什么要用 Service 而不是 Thread

為什么要用 Service 而不是 Thread
  • Thread 的運(yùn)行是獨(dú)立于 Activity 的,也就是當(dāng)一個(gè) Activityfinish 之后,如果沒有主動(dòng)停止 Thread 或者 Thread 中的 run 沒有執(zhí)行完畢時(shí)那么這個(gè)線程會(huì)一直執(zhí)行下去。
  • 因此這里會(huì)出現(xiàn)一個(gè)問題:當(dāng) Activityfinish 之后,你不再持有該 Thread 的引用。
  • 另一方面,你沒有辦法在不同的 Activity 中對同一 Thread 進(jìn)行控制。

3.3 Service 里面是否能執(zhí)行耗時(shí)的操作

Service 里面是否能執(zhí)行耗時(shí)的操作
  • service 里面不能執(zhí)行耗時(shí)的操作(網(wǎng)絡(luò)請求,拷貝數(shù)據(jù)庫,大文件 )

  • Service 不是獨(dú)立的進(jìn)程,也不是獨(dú)立的線程,它是依賴于應(yīng)用程序的主線程的,也就是說,在更多時(shí)候不建議在 Service 中編寫耗時(shí)的邏輯和操作(比如:網(wǎng)絡(luò)請求,拷貝數(shù)據(jù)庫,大文件),否則會(huì)引起 ANR 。

  • 如果想在服務(wù)中執(zhí)行耗時(shí)的任務(wù)。有以下解決方案:

  1. service 中開啟一個(gè)子線程
new Thread(){}.start();
  1. 可以使用 IntentService 異步管理服務(wù)( 有關(guān) IntentService 的內(nèi)容在后文中給出 )

3.4 Service 是否在 main thread 中執(zhí)行

Service 是否在 main thread 中執(zhí)行
  • 默認(rèn)情況, 如果沒有顯示的指 service 所運(yùn)行的進(jìn)程, Serviceactivity 是運(yùn) 行在當(dāng)前 app 所在進(jìn)程的 main thread ( UI 主線程)里面。
  • ServiceActivity 在同一個(gè)線程,對于同一 app 來說默認(rèn)情況下是在同一個(gè)線程中的 main Thread ( UI Thread )
  • 特殊情況 ,可以在清單文件配置 service 執(zhí)行所在的進(jìn)程 ,讓 service 在另 外的進(jìn)程中執(zhí)行 Service 不死之身

3.4.1 在 onStartCommand 方法中將 flag 設(shè)置為 START_STICKY ;

<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >
</service>
return Service.START_STICKY;

3.4.2 在 xml 中設(shè)置了 android:priority

<!--設(shè)置服務(wù)的優(yōu)先級為MAX_VALUE-->
 <service android:name=".MyService"
          android:priority="2147483647"
          >
 </service>

3.4.3 在 onStartCommand 方法中設(shè)置為前臺(tái)進(jìn)程

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  Notification notification = new Notification(R.mipmap.ic_launcher, "服務(wù)正在運(yùn)行",System.currentTimeMillis());
   Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent,0);
    RemoteViews remoteView = new RemoteViews(this.getPackageName(),R.layout.notification);
    remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
    remoteView.setTextViewText(R.id.text , "Hello,this message is in a custom expanded view");
    notification.contentView = remoteView;
    notification.contentIntent = pendingIntent;
    startForeground(1, notification);
    return Service.START_STICKY;
}

3.4.4 在 onDestroy 方法中重啟 service

@Override
public void onDestroy() {
    super.onDestroy();
    startService(new Intent(this, MyService.class));
}

3.4.5 用 AlarmManager.setRepeating(…) 方法循環(huán)發(fā)送鬧鐘廣播, 接收的時(shí)候調(diào)用 serviceonStartCommand 方法

Intent intent = new Intent(MainActivity.this,MyAlarmReciver.class);
PendingIntent sender = PendingIntent.getBroadcast( MainActivity.this, 0, intent, 0);

// We want the alarm to go off 10 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
//重復(fù)鬧鐘
/**
 *  @param type
 * @param triggerAtMillis t 鬧鐘的第一次執(zhí)行時(shí)間,以毫秒為單位
 * go off, using the appropriate clock (depending on the alarm type).
 * @param intervalMillis 表示兩次鬧鐘執(zhí)行的間隔時(shí)間,也是以毫秒為單位
 * of the alarm.
 * @param operation 綁定了鬧鐘的執(zhí)行動(dòng)作,比如發(fā)送一個(gè)廣播、給出提示等等
 */
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2 * 1000, sender);

3.4.6 目前市場面的很多三方的消息推送 SDK 喚醒 APP , 例如 Jpush

PS: 以上這些方法并不代表著你的 Service 就永生不死了,只能說是提高了進(jìn)程的優(yōu)先級。迄今為止我沒有發(fā)現(xiàn)能夠通過常規(guī)方法達(dá)到流氓需求 (通過長按 home 鍵清除都清除不掉) 的方法,目前所有方法都是指通過 Android 的內(nèi)存回收機(jī)制和普通的第三方內(nèi)存清除等手段后仍然保持運(yùn)行的方法,有些手機(jī)廠商把這些知名的 app 放入了自己的白名單中,保證了進(jìn)程不死來提高用戶體驗(yàn)(如微信、QQ 、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通 app 一樣躲避不了被殺的命運(yùn)。

第四篇:InterService


  • 作為一個(gè)老司機(jī),如果連 Interservice 都沒聽說過,那就有點(diǎn)那個(gè)啥了
InterService

4.1 什么是 IntentService

什么是 IntentService
  • IntentServiceService 的子類,比普通的 Service 增加了額外的功能。

  • 我們常用的 Service 存在兩個(gè)問題:

  1. Service 不會(huì)專門啟動(dòng)一條單獨(dú)的進(jìn)程,Service 與它所在應(yīng)用位于同一個(gè)進(jìn)程中

  2. Service 也不是專門一條新線程,因此不應(yīng)該在 Service 中直接處理耗時(shí)的任務(wù)

4.2 IntentService 的特征

IntentService 的特征
  • 會(huì)創(chuàng)建獨(dú)立的 worker 線程來處理所有的 Intent 請求

  • 會(huì)創(chuàng)建獨(dú)立的 worker 線程來處理 onHandleIntent() 方法實(shí)現(xiàn)的代碼,無需處理多線程問題

  • 所有請求處理完成后,IntentService 會(huì)自動(dòng)停止,無需調(diào)用 stopSelf() 方法停止 Service

  • ServiceonBind() 提供默認(rèn)實(shí)現(xiàn),返回 null

  • ServiceonStartCommand 提供默認(rèn)實(shí)現(xiàn),將請求 Intent 添加到隊(duì)列中

4.3 Service 和 IntentService 區(qū)別

Service 和 IntentService 區(qū)別

4.3.1 Service 是用于后臺(tái)服務(wù)的

Service 是用于后臺(tái)服務(wù)的
  1. 當(dāng)應(yīng)用程序被掛到后臺(tái)的時(shí)候,為了保證應(yīng)用某些組件仍然可以工作而引入了 Service 這個(gè)概念
  2. 那么這里面要強(qiáng)調(diào)的是:Service 不是獨(dú)立的進(jìn)程,也不是獨(dú)立的線程,它是依賴于應(yīng)用程序的主線程的,也就是說,在更多時(shí)候不建議在 Service 中編寫耗時(shí)的邏輯和操作,否則會(huì)引起 ANR 。

也就是,service 里面不可以進(jìn)行耗時(shí)的操作。雖然在后臺(tái)服務(wù)。但是也是在主線程里面。

4.3.2 當(dāng)我們編寫的耗時(shí)邏輯,不得不被 service 來管理的時(shí)候,就需要引入 IntentService 。

耗時(shí)邏輯
  1. IntentService 是繼承 Service 的,那么它包含了 Service 的全部特性,當(dāng)然也包含 service 的生命周期。
  2. 那么與 service 不同的是,IntentService 在執(zhí)行 onCreate 操作的時(shí)候,內(nèi)部開了一個(gè)線程,去你執(zhí)行你的耗時(shí)操作。

4.3.3 使用:

使用
  1. 重寫 protected abstract void onHandleIntent(Intent intent)

4.3.4 IntentService 是一個(gè)通過 Context.startService(Intent) 啟動(dòng)可以處理異步請求的 Service

通過 Context.startService(Intent) 啟動(dòng)
  1. 使用時(shí)你只需要繼承 IntentService 和重寫其中的 onHandleIntent(Intent) 方法接收一個(gè) Intent 對象 , 在適當(dāng)?shù)臅r(shí)候會(huì)停止自己 ( 一般在工作完成的時(shí)候 ) 。
  2. 所有的請求的處理都在一個(gè)工作線程中完成 , 它們會(huì)交替執(zhí)行 ( 但不會(huì)阻塞主線程的執(zhí)行 ) ,一次只能執(zhí)行一個(gè)請求。

4.3.5 是一個(gè)基于消息的服務(wù)

是一個(gè)基于消息的服務(wù)
  1. 每次啟動(dòng)該服務(wù)并不是馬上處理你的工作,而是首先會(huì)創(chuàng)建對應(yīng)的 Looper ,Handler 并且在 MessageQueue 中添加的附帶客戶 IntentMessage 對象。
  2. 當(dāng) Looper 發(fā)現(xiàn)有 Message 的時(shí)候接著得到 Intent 對象通過在 onHandleIntent((Intent)msg.obj) 中調(diào)用你的處理程序,處理完后即會(huì)停止自己的服務(wù)。
  3. 意思是 Intent 的生命周期跟你的處理的任務(wù)是一致的,所以這個(gè)類用下載任務(wù)中非常好,下載任務(wù)結(jié)束后服務(wù)自身就會(huì)結(jié)束退出。

4.3.6 總結(jié) IntentService 的特征有:

總結(jié) IntentService 的特征
  1. 會(huì)創(chuàng)建獨(dú)立的 worker 線程來處理所有的 Intent 請求;

  2. 會(huì)創(chuàng)建獨(dú)立的 worker 線程來處理 onHandleIntent() 方法實(shí)現(xiàn)的代碼,無需處理多線程問題;

  3. 所有請求處理完成后,IntentService會(huì)自動(dòng)停止,無需調(diào)用 stopSelf() 方法停止 Service ;

第五篇:Service 與 Activity


Service 與 Activity

5.1 Activity 怎么和 Service 綁定,怎么在 Activity 中啟動(dòng)對應(yīng)的 Service

Service 與 Activity
  • Activity 通過 bindService(Intent service, ServiceConnection conn, int flags)Service 進(jìn)行綁定,當(dāng)綁定成功的時(shí)候 Service 會(huì)將代理對象通過回調(diào)的形式傳給 conn ,這樣我們就拿到了 Service 提供的服務(wù)代理對象。

  • Activity 中可以通過 startServicebindService 方法啟動(dòng) Service。一般情況下如果想獲取 Service 的服務(wù)對象那么肯定需要通過 bindService() 方法,比如音樂播放器,第三方支付等。

  • 如果僅僅只是為了開啟一個(gè)后臺(tái)任務(wù)那么可以使用 startService() 方法。

5.2 說說 Activity 、Intent 、Service 是什么關(guān)系

Activity 、Intent 、Service 是什么關(guān)系
  • 他們都是 Android 開發(fā)中使用頻率最高的類。其中 ActivityService 都屬于 Android 的四大組件。他倆都是 Context 類的子類 ContextWrapper 的子類,因此他倆可以算是兄弟關(guān)系吧。

  • 不過他們各有各自的本領(lǐng),Activity 負(fù)責(zé)用戶界面的顯示和交互,Service 負(fù)責(zé)后臺(tái)任務(wù)的處理。

  • ActivityService 之間可以通過 Intent 傳遞數(shù)據(jù),因此可以把 Intent 看作是通信使者。

5.3 Service 和 Activity 在同一個(gè)線程嗎

Service 和 Activity 在同一個(gè)線程嗎

對于同一 app 來說默認(rèn)情況下是在同一個(gè)線程中的,main ThreadUI Thread )。

5.4 Service 里面可以彈吐司么

Service 里面可以彈吐司么
  • 可以
  • 彈吐司有個(gè)條件是:得有一個(gè) Context 上下文,而 Service 本身就是 Context 的子類
  • 因此在 Service 里面彈吐司是完全可以的。比如我們在 Service 中完成下載任務(wù)后可以彈一個(gè)吐司通知給用戶。

5.5 與 Service 交互方式

與 Service 交互方式

5.5.1 廣播交互

廣播交互
  1. Server 端將目前的下載進(jìn)度,通過廣播的方式發(fā)送出來,Client 端注冊此廣播的監(jiān)聽器,當(dāng)獲取到該廣播后,將廣播中當(dāng)前的下載進(jìn)度解析出來并更新到界面上。
  2. 定義自己的廣播,這樣在不同的 Activity 、Service 以及應(yīng)用程序之間,就可以通過廣播來實(shí)現(xiàn)交互。

5.5.2 共享文件交互

共享文件交互
  1. 我們使用 SharedPreferences 來實(shí)現(xiàn)共享,當(dāng)然也可以使用其它 IO 方法實(shí)現(xiàn),通過這種方式實(shí)現(xiàn)交互時(shí)需要注意,對于文件的讀寫的時(shí)候,同一時(shí)間只能一方讀一方寫,不能兩方同時(shí)寫。
  2. Server 端將當(dāng)前下載進(jìn)度寫入共享文件中,Client 端通過讀取共享文件中的下載進(jìn)度,并更新到主界面上。

5.5.3 Messenger 交互 ( 信使交互 )

Messenger 交互 ( 信使交互 )
  1. Messenger 翻譯過來指的是信使,它引用了一個(gè) Handler 對象,別人能夠向它發(fā)送消息 ( 使用 mMessenger.send ( Message msg ) 方法)。
  2. 該類允許跨進(jìn)程間基于 Message 通信,在服務(wù)端使用 Handler 創(chuàng)建一個(gè) Messenger ,客戶端只要獲得這個(gè)服務(wù)端的 Messenger 對象就可以與服務(wù)端通信了
  3. Server 端與 Client 端之間通過一個(gè) Messenger 對象來傳遞消息,該對象類似于信息中轉(zhuǎn)站,所有信息通過該對象攜帶

5.5.4 自定義接口交互

自定義接口交互
  1. 其實(shí)就是我們自己通過接口的實(shí)現(xiàn)來達(dá)到 ActivityService 交互的目的,我們通過在 ActivityService 之間架設(shè)一座橋樑,從而達(dá)到數(shù)據(jù)交互的目的,而這種實(shí)現(xiàn)方式和 AIDL 非常類似
  2. 自定義一個(gè)接口,該接口中有一個(gè)獲取當(dāng)前下載進(jìn)度的空方法。Server 端用一個(gè)類繼承自 Binder 并實(shí)現(xiàn)該接口,覆寫了其中獲取當(dāng)前下載進(jìn)度的方法。Client 端通過 ServiceConnection 獲取到該類的對象,從而能夠使用該獲取當(dāng)前下載進(jìn)度的方法,最終實(shí)現(xiàn)實(shí)時(shí)交互。

5.5.5 AIDL 交互

AIDL交互
  1. 遠(yuǎn)程服務(wù)一般通過 AIDL 來實(shí)現(xiàn),可以進(jìn)行進(jìn)程間通信,這種服務(wù)也就是遠(yuǎn)程服務(wù)。
  2. AIDL 屬于 AndroidIPC 機(jī)制,常用于跨進(jìn)程通信,主要實(shí)現(xiàn)原理基于底層 Binder 機(jī)制。

第六篇:使用


使用

6.1 什么情況下會(huì)使用 Service

什么情況下會(huì)使用 Service

6.1.1 經(jīng)驗(yàn)總結(jié):

經(jīng)驗(yàn)總結(jié)
  1. Service 其實(shí)就是背地搞事情,又不想讓別人知道
  2. 舉一個(gè)生活當(dāng)中的例子,你想知道一件事情不需要直接去問,你可以通過側(cè)面了解。這就是 Service 設(shè)計(jì)的初衷

6.1.2 Service 為什么被設(shè)計(jì)出來

Service 為什么被設(shè)計(jì)出來
  1. 根據(jù) Service 的定義,我們可以知道需要長期在后臺(tái)進(jìn)行的工作我們需要將其放在 Service 中去做。
  2. 得再通熟易懂一點(diǎn),就是不能放在 Activity 中來執(zhí)行的工作就必須得放到 Service 中去做。
  3. 如:音樂播放、下載、上傳大文件、定時(shí)關(guān)閉應(yīng)用等功能。這些功能如果放到 Activity 中做的話,那么 Activity 退出被銷毀了的話,那這些功能也就停止了,這顯然是不符合我們的設(shè)計(jì)要求的,所以要將他們放在 Service 中去執(zhí)行。

6.2 onStartCommand() 返回值 int 值的區(qū)別

  • 有四種返回值,不同值代表的意思如下:
onStartCommand() 返回值 int 值的區(qū)別

6.2.1 START_STICKY :

  1. 如果 service 進(jìn)程被 kill 掉,保留 service 的狀態(tài)為開始狀態(tài),但不保留遞送的 intent 對象。
  2. 隨后系統(tǒng)會(huì)嘗試重新創(chuàng)建 service, 由于服務(wù)狀態(tài)為開始狀態(tài),所以創(chuàng)建服務(wù)后一定會(huì)調(diào)用 onStartCommand ( Intent, int, int ) 方法。
  3. 如果在此期間沒有任何啟動(dòng)命令被傳遞到 service , 那么參數(shù) Intent 將為 null 。

6.2.2 START_NOT_STICKY :

  1. “非粘性的”。
  2. 使用這個(gè)返回值時(shí) , 如果在執(zhí)行完 onStartCommand 后 , 服務(wù)被異常 kill 掉 ,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)。

6.2.3 START_REDELIVER_INTENT:

  1. 重傳 Intent
  2. 使用這個(gè)返回值時(shí),如果在執(zhí)行完 onStartCommand 后,服務(wù)被異常 kill 掉
  3. 系統(tǒng)會(huì)自動(dòng)重啟該服務(wù) , 并將 Intent 的值傳入。

6.2.4 START_STICKY_COMPATIBILITY:

  1. START_STICKY 的兼容版本 , 但不保證服務(wù)被 kill 后一定能重啟。

6.3 在 service 的生命周期方法 onstartConmand() 可不可以執(zhí)行網(wǎng)絡(luò)操作?如何在 service 中執(zhí)行網(wǎng)絡(luò)操作?

onstartConmand() 可不可以執(zhí)行網(wǎng)絡(luò)操作?如何在 service 中執(zhí)行網(wǎng)絡(luò)操作?
  • 可以直接在 Service 中執(zhí)行網(wǎng)絡(luò)操作
  • onStartCommand() 方法中可以執(zhí)行網(wǎng)絡(luò)操作

6.4 提高 service 的優(yōu)先級

提高 service 的優(yōu)先級
  • AndroidManifest.xml 文件中對于 intent-filter 可以通過 android:priority = “1000” 這個(gè)屬性設(shè)置最高優(yōu)先級,1000 是最高值,如果數(shù)字越小則優(yōu)先級越低,同時(shí)實(shí)用于廣播。

  • onStartCommand 里面調(diào)用 startForeground() 方法把 Service 提升為前臺(tái)進(jìn)程級別,然后再 onDestroy 里面要記得調(diào)用 stopForeground () 方法。

  • onStartCommand 方法,手動(dòng)返回 START_STICKY

廣播
  • onDestroy 方法里發(fā)廣播重啟 service 。
  1. service + broadcast 方式,就是當(dāng) serviceondestory 的時(shí)候,發(fā)送一個(gè)自定義的廣播
  2. 當(dāng)收到廣播的時(shí)候,重新啟動(dòng) service 。( 第三方應(yīng)用或是在 setting 里-應(yīng)用強(qiáng)制停止時(shí),APP 進(jìn)程就直接被干掉了,onDestroy 方法都進(jìn)不來,所以無法保證會(huì)執(zhí)行 )
  • 監(jiān)聽系統(tǒng)廣播判斷 Service 狀態(tài)。
  1. 通過系統(tǒng)的一些廣播
  2. 比如:手機(jī)重啟、界面喚醒、應(yīng)用狀態(tài)改變等等監(jiān)聽并捕獲到,然后判斷我們的 Service 是否還存活。
  • Application 加上 Persistent 屬性。

6.5 Service 的 onRebind ( Intent ) 方法在什么情況下會(huì)執(zhí)行

onRebind ( Intent ) 方法在什么情況下會(huì)執(zhí)行
  • 如果在 onUnbind() 方法返回 true 的情況下會(huì)執(zhí)行 , 否則不執(zhí)行。

總結(jié)


  1. 本文基本涵蓋了 Android Service 相關(guān)的知識(shí)點(diǎn)。由于篇幅原因,諸如 InterService 具體使用方法等,沒辦法詳細(xì)的介紹,大家很容易就能在網(wǎng)上找到資料進(jìn)行學(xué)習(xí)。
  2. 重點(diǎn):關(guān)于 Android 的四大組件,到現(xiàn)在為止我才總結(jié)完 ActivityService,我將繼續(xù)針對,BroadcastRecevier ContentProvider 等,以及四大組件之外的,事件分發(fā)、滑動(dòng)沖突、新能優(yōu)化等重要模塊,進(jìn)行全面總結(jié),歡迎大家關(guān)注 _yuanhao 的 簡書,方便及時(shí)接收更新
  3. 開始前還以為總結(jié)不難,實(shí)際寫文章的過程中,才知道什么是艱辛。也不知道自己能不能咬牙堅(jiān)持下去,希望大家給我鼓勵(lì),就算只是一個(gè)贊,也是我堅(jiān)持下去的理由!

碼字不易,你的點(diǎn)贊是我總結(jié)的最大動(dòng)力!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容