Android
有一段時間了,想必很多人也和我同樣,平時常常東學西湊,感受知識點有些凌亂難成體系。因此趁着這幾天忙裏偷閒,把學的東西概括下,捋捋思路。這篇文章主要針對
Service
相關的知識點,進行詳細的梳理,祝你們食用愉快!html
倉庫內容與博客同步更新。因爲我在 稀土掘金
簡書
CSDN
博客園
等站點,都有新內容發佈。因此你們能夠直接關注該倉庫,以避免錯過精彩內容!java
倉庫地址: 超級乾貨!精心概括 Android
、JVM
、算法等,各位帥氣的老鐵支持一下!給個 Star !android
Service
(服務) 是一個一種能夠在後臺執行長時間運行操做而沒有用戶界面的應用組件。Activity
),服務一旦被啓動將在後臺一直運行,即便啓動服務的組件( Activity
)已銷燬也不受影響。IPC
)。UI
界面Service
的適用場景應該具有如下條件:並不依賴於用戶可視的 UI
界面(固然,這一條其實也不是絕對的,如前臺 Service
就是與 Notification
界面結合使用的)git
具備較長時間的運行特性github
注意: 是運行在主線程當中的面試
服務進程是經過 startService()
方法啓動的進程,但不屬於前臺進程和可見進程。例如,在後臺播放音樂或者在後臺下載就是服務進程。算法
系統保持它們運行,除非沒有足夠內存來保證全部的前臺進程和可視進程。數據庫
Service
的生命週期 的基本流程定義一個類繼承 Service
微信
在 Manifest.xml
文件中配置該 Service
網絡
使用 Context
的 startService(intent)
方法開啓服務。
使用 Context
的 stopService(intent)
方法關閉服務。
該啓動方式,app
殺死、Activity
銷燬沒有任何影響,服務不會中止銷燬。
建立 BindService
服務端,繼承 Service
並在類中,建立一個實現 IBinder
接口的實例對象,並提供公共方法給客戶端( Activity
)調用。
從 onBinder()
回調方法返回該 Binder
實例。
在客戶端( Activity
)中, 從 onServiceConnection()
回調方法參數中接收 Binder
,經過 Binder
對象便可訪問 Service
內部的數據。
在 manifests
中註冊 BindService
, 在客戶端中調用 bindService()
方法開啓綁定 Service
, 調用 unbindService()
方法註銷解綁 Service
。
該啓動方式依賴於客戶端生命週期,當客戶端 Activity
銷燬時, 沒有調用 unbindService()
方法 , Service
也會中止銷燬。
在 Service
的生命週期中,被回調的方法比 Activity
少一些,只有 onCreate
, onStart
, onDestroy
, onBind
和 onUnbind
。
一般有兩種方式啓動一個 Service
, 他們對 Service
生命週期的影響是不同的。
startService
Service
會經歷 onCreate
到 onStart
,而後處於運行狀態,stopService
的時候調用 onDestroy
方法。若是是調用者本身直接退出而沒有調用
stopService
的話,Service
會一直在後臺運行。
bindService
Service
會運行 onCreate
,而後是調用 onBind
, 這個時候調用者和 Service
綁定在一塊兒。調用者退出了,Srevice
就會調用 onUnbind
-> onDestroyed
方法。
所謂綁定在一塊兒就共存亡了。調用者也能夠經過調用
unbindService
方法來中止服務,這時候Srevice
就會調用onUnbind
->onDestroyed
方法。
一個原則是 Service
的 onCreate
的方法只會被調用一次,就是你不管多少次的 startService
又 bindService
,Service
只被建立一次。
若是先是 bind
了,那麼 start
的時候就直接運行 Service
的 onStart
方法,若是先是 start
,那麼 bind
的時候就直接運行 onBind
方法。
若是 service
運行期間調用了 bindService
,這時候再調用 stopService
的話,service
是不會調用 onDestroy
方法的,service
就 stop
不掉了,只能調用 UnbindService
, service
就會被銷燬
若是一個 service
經過 startService
被 start
以後,屢次調用 startService
的話,service
會屢次調 用 onStart
方法。屢次調用 stopService
的話,service
只會調用一次 onDestroyed
方法。
若是一個 service
經過 bindService
被 start
以後,屢次調用 bindService
的話,service
只會調用一次 onBind
方法。屢次調用 unbindService
的話會拋出異常。
thread
是程序執行的最小單元,他是分配 cpu
的基本單位安卓系統中,咱們常說的主線程,UI
線程,也是線程的一種。固然,線程裏面還能夠執行一些耗時的異步操做。service
你們記住,它是安卓中的一種特殊機制,service
是運行在主線程當中的,因此說它不能作耗時操做,它是由系統進程託管,其實 service
也是一種輕量級的 IPC
通訊,由於 activity
能夠和 service
綁定,能夠和 service
進行數據通訊。activity
和 service
是處於不一樣的進程當中,因此說它們之間的數據通訊,要經過 IPC
進程間通訊的機制來進行操做。UI
線程的繪製,UI
線程裏面絕對不能作耗時操做,這裏是最基本最重要的一點。(這是 Thread
在實際開發過程中的應用)service
是安卓當中,四大組件之一,通常狀況下也是運行在主線程當中,所以 service
也是不能夠作耗時操做的,不然系統會報 ANR 異常( ANR
全稱:Application Not Responding
),就是程序沒法作出響應。service
裏面進行耗時操做,必定要記得開啓單獨的線程去作。UI
線程的時候,都應該使用工做線程,也就是開啓一個子線程的方式。UI
線程不被佔用,而影響用戶體驗。service
來講,咱們常常須要長時間在後臺運行,並且不須要進行交互的狀況下才會使用到服務,好比說,咱們在後臺播放音樂,開啓天氣預報的統計,還有一些數據的統計等等。Thread
的運行是獨立於 Activity
的,也就是當一個 Activity
被 finish
以後,若是沒有主動中止 Thread
或者 Thread
中的 run
沒有執行完畢時那麼這個線程會一直執行下去。Activity
被 finish
以後,你再也不持有該 Thread
的引用。Activity
中對同一 Thread
進行控制。service 裏面不能執行耗時的操做(網絡請求,拷貝數據庫,大文件 )
Service
不是獨立的進程,也不是獨立的線程,它是依賴於應用程序的主線程的,也就是說,在更多時候不建議在 Service
中編寫耗時的邏輯和操做(好比:網絡請求,拷貝數據庫,大文件),不然會引發 ANR
。
若是想在服務中執行耗時的任務。有如下解決方案:
service
中開啓一個子線程new Thread(){}.start();
複製代碼
IntentService
異步管理服務( 有關 IntentService
的內容在後文中給出 )service
所運行的進程, Service
和 activity
是運 行在當前 app
所在進程的 main thread
( UI
主線程)裏面。Service
和 Activity
在同一個線程,對於同一 app
來講默認狀況下是在同一個線程中的 main Thread
( UI Thread
)service
執行所在的進程 ,讓 service
在另 外的進程中執行 Service
不死之身onStartCommand
方法中將 flag
設置爲 START_STICKY
;<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >
</service>
複製代碼
return Service.START_STICKY;
複製代碼
android:priority
<!--設置服務的優先級爲MAX_VALUE-->
<service android:name=".MyService" android:priority="2147483647" >
</service>
複製代碼
onStartCommand
方法中設置爲前臺進程@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification(R.mipmap.ic_launcher, "服務正在運行",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;
}
複製代碼
onDestroy
方法中重啓 service
@Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, MyService.class));
}
複製代碼
AlarmManager.setRepeating(…)
方法循環發送鬧鐘廣播, 接收的時候調用 service
的 onstart
方法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);
//重複鬧鐘
/** * @param type * @param triggerAtMillis t 鬧鐘的第一次執行時間,以毫秒爲單位 * go off, using the appropriate clock (depending on the alarm type). * @param intervalMillis 表示兩次鬧鐘執行的間隔時間,也是以毫秒爲單位 * of the alarm. * @param operation 綁定了鬧鐘的執行動做,好比發送一個廣播、給出提示等等 */
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2 * 1000, sender);
複製代碼
SDK
喚醒 APP
, 例如 Jpush
PS
: 以上這些方法並不表明着你的Service
就永生不死了,只能說是提升了進程的優先級。迄今爲止我沒有發現可以經過常規方法達到流氓需求 (經過長按home
鍵清除都清除不掉) 的方法,目前全部方法都是指經過Android
的內存回收機制和普通的第三方內存清除等手段後仍然保持運行的方法,有些手機廠商把這些知名的app
放入了本身的白名單中,保證了進程不死來提升用戶體驗(如微信、app
同樣躲避不了被殺的命運。
Interservice
都沒據說過,那就有點那個啥了IntentService
是 Service
的子類,比普通的 Service
增長了額外的功能。
咱們經常使用的 Service
存在兩個問題:
Service
不會專門啓動一條單獨的進程,Service
與它所在應用位於同一個進程中
Service
也不是專門一條新線程,所以不該該在 Service
中直接處理耗時的任務
會建立獨立的 worker
線程來處理全部的 Intent
請求
會建立獨立的 worker
線程來處理 onHandleIntent()
方法實現的代碼,無需處理多線程問題
全部請求處理完成後,IntentService
會自動中止,無需調用 stopSelf()
方法中止 Service
爲 Service
的 onBind()
提供默認實現,返回 null
爲 Service
的 onStartCommand
提供默認實現,將請求 Intent
添加到隊列中
Service
是用於後臺服務的Service
這個概念Service
不是獨立的進程,也不是獨立的線程,它是依賴於應用程序的主線程的,也就是說,在更多時候不建議在 Service
中編寫耗時的邏輯和操做,不然會引發 ANR
。也就是,service 裏面不能夠進行耗時的操做。雖然在後臺服務。可是也是在主線程裏面。
service
來管理的時候,就須要引入 IntentService
。IntentService
是繼承 Service
的,那麼它包含了 Service
的所有特性,固然也包含 service
的生命週期。service
不一樣的是,IntentService
在執行 onCreate
操做的時候,內部開了一個線程,去你執行你的耗時操做。protected abstract void onHandleIntent(Intent intent)
IntentService
是一個經過 Context.startService(Intent)
啓動能夠處理異步請求的 Service
IntentService
和重寫其中的 onHandleIntent(Intent)
方法接收一個 Intent
對象 , 在適當的時候會中止本身 ( 通常在工做完成的時候 ) 。Looper
,Handler
而且在 MessageQueue
中添加的附帶客戶 Intent
的 Message
對象。Looper
發現有 Message
的時候接着獲得 Intent
對象經過在 onHandleIntent((Intent)msg.obj)
中調用你的處理程序,處理完後即會中止本身的服務。Intent
的生命週期跟你的處理的任務是一致的,因此這個類用下載任務中很是好,下載任務結束後服務自身就會結束退出。IntentService
的特徵有:會建立獨立的 worker
線程來處理全部的 Intent
請求;
會建立獨立的 worker
線程來處理 onHandleIntent()
方法實現的代碼,無需處理多線程問題;
全部請求處理完成後,IntentService
會自動中止,無需調用 stopSelf()
方法中止 Service
;
Activity
經過 bindService(Intent service, ServiceConnection conn, int flags)
跟 Service
進行綁定,當綁定成功的時候 Service
會將代理對象經過回調的形式傳給 conn
,這樣咱們就拿到了 Service
提供的服務代理對象。
在 Activity
中能夠經過 startService
和 bindService
方法啓動 Service
。通常狀況下若是想獲取 Service
的服務對象那麼確定須要經過 bindService()
方法,好比音樂播放器,第三方支付等。
若是僅僅只是爲了開啓一個後臺任務那麼可使用 startService()
方法。
他們都是 Android
開發中使用頻率最高的類。其中 Activity
和 Service
都屬於 Android
的四大組件。他倆都是 Context
類的子類 ContextWrapper
的子類,所以他倆能夠算是兄弟關係吧。
不過他們各有各自的本領,Activity
負責用戶界面的顯示和交互,Service
負責後臺任務的處理。
Activity
和 Service
之間能夠經過 Intent
傳遞數據,所以能夠把 Intent
看做是通訊使者。
對於同一 app
來講默認狀況下是在同一個線程中的,main Thread
( UI Thread
)。
Context
上下文,而 Service
自己就是 Context
的子類Service
裏面彈吐司是徹底能夠的。好比咱們在 Service
中完成下載任務後能夠彈一個吐司通知給用戶。Server
端將目前的下載進度,經過廣播的方式發送出來,Client
端註冊此廣播的監聽器,當獲取到該廣播後,將廣播中當前的下載進度解析出來並更新到界面上。Activity
、Service
以及應用程序之間,就能夠經過廣播來實現交互。SharedPreferences
來實現共享,固然也可使用其它 IO
方法實現,經過這種方式實現交互時須要注意,對於文件的讀寫的時候,同一時間只能一方讀一方寫,不能兩方同時寫。Server
端將當前下載進度寫入共享文件中,Client
端經過讀取共享文件中的下載進度,並更新到主界面上。Messenger
交互 ( 信使交互 )Messenger
翻譯過來指的是信使,它引用了一個 Handler
對象,別人可以向它發送消息 ( 使用 mMessenger.send ( Message msg )
方法)。Message
通訊,在服務端使用 Handler
建立一個 Messenger
,客戶端只要得到這個服務端的 Messenger
對象就能夠與服務端通訊了Server
端與 Client 端之間經過一個 Messenger
對象來傳遞消息,該對象相似於信息中轉站,全部信息經過該對象攜帶Activity
與 Service
交互的目的,咱們經過在 Activity
和 Service
之間架設一座橋樑,從而達到數據交互的目的,而這種實現方式和 AIDL
很是相似Server
端用一個類繼承自 Binder
並實現該接口,覆寫了其中獲取當前下載進度的方法。Client
端經過 ServiceConnection
獲取到該類的對象,從而可以使用該獲取當前下載進度的方法,最終實現實時交互。AIDL
交互AIDL
來實現,能夠進行進程間通訊,這種服務也就是遠程服務。AIDL
屬於 Android
的 IPC
機制,經常使用於跨進程通訊,主要實現原理基於底層 Binder
機制。Service
其實就是背地搞事情,又不想讓別人知道Service
設計的初衷Service
爲何被設計出來Service
的定義,咱們能夠知道須要長期在後臺進行的工做咱們須要將其放在 Service
中去作。Activity
中來執行的工做就必須得放到 Service
中去作。Activity
中作的話,那麼 Activity
退出被銷燬了的話,那這些功能也就中止了,這顯然是不符合咱們的設計要求的,因此要將他們放在 Service
中去執行。START_STICKY
:service
進程被 kill 掉,保留 service
的狀態爲開始狀態,但不保留遞送的 intent
對象。service
, 因爲服務狀態爲開始狀態,因此建立服務後必定會調用 onStartCommand ( Intent, int, int )
方法。service
, 那麼參數 Intent
將爲 null
。START_NOT_STICKY
:onStartCommand
後 , 服務被異常 kill
掉 ,系統不會自動重啓該服務。START_REDELIVER_INTENT
:Intent
。onStartCommand
後,服務被異常 kill 掉START_STICKY_COMPATIBILITY
:START_STICKY
的兼容版本 , 但不保證服務被 kill
後必定能重啓。Service
中執行網絡操做onStartCommand()
方法中能夠執行網絡操做在 AndroidManifest.xml
文件中對於 intent-filter
能夠經過 android:priority = 「1000」
這個屬性設置最高優先級,1000
是最高值,若是數字越小則優先級越低,同時實用於廣播。
在 onStartCommand
裏面調用 startForeground()
方法把 Service
提高爲前臺進程級別,而後再 onDestroy
裏面要記得調用 stopForeground ()
方法。
onStartCommand
方法,手動返回 START_STICKY
。
onDestroy
方法裏發廣播重啓 service
。service
+ broadcast
方式,就是當 service
走 ondestory
的時候,發送一個自定義的廣播service
。( 第三方應用或是在 setting
裏-應用強制中止時,APP
進程就直接被幹掉了,onDestroy
方法都進不來,因此沒法保證會執行 )Service
狀態。Service
是否還存活。Application
加上 Persistent
屬性。onUnbind()
方法返回 true
的狀況下會執行 , 不然不執行。Android Service
相關的知識點。因爲篇幅緣由,諸如 InterService 具體使用方法等,沒辦法詳細的介紹,你們很容易就能在網上找到資料進行學習。重點
:關於 Android
的四大組件,到如今爲止我才總結完 Activity
和 Service
,我將繼續針對,BroadcastRecevier
ContentProvider
等,以及四大組件以外的,事件分發、滑動衝突、新能優化等重要模塊,進行全面總結,歡迎你們關注 _yuanhao 的 掘金 ,方便及時接收更新因爲我在「稀土掘金」「簡書」「CSDN
」「博客園」等站點,都有新內容發佈。因此你們能夠直接關注個人 GitHub
倉庫,以避免錯過精彩內容!
1W
多字長文,加上精美思惟導圖,記得點贊哦,歡迎關注 _yuanhao 的 掘金
相關文章都可在個人主頁、GitHub 上看到,這裏限於篇幅緣由,也爲了保持界面整潔,讓你們能有跟舒心的閱讀體驗就不給出了,咱們下篇文章不見不散!