[轉] Android LocalService與RemoteService理解


前段時間被別人問到相關的問題,沒有回答對,發現自己原來理解的有偏差,最近看了下,寫了個小Demo實驗了下,現在將其記錄下來,以后千萬別犯同樣的錯誤就好了。

一、LocalService(本地服務)

不需要和Activity交互的本地服務:使用startService和stopService。

運行時 可以發現第一次startService時,會調用onCreate和onStartCommand,在沒有stopService之前,無論點擊多少次 startService,都只會調用onStartCommand,而stopService時調用onDestory。再次點擊 stopService,會發現不會進入service的生命周期,即不會再調用onCreate、onStart和onDestory。而onBind 在startService和stopService中沒有調用。

需要和Activity交互的本地服務:使用

在繼承的Service類中,可以發現onBind需要返回一個IBinder對象,也就是說和startService不同的是:

1、添加一個public內部類繼承Binder,並添加getService方法來返回當前Service對象

2、新建一個IBinder對象----new那個Binder內部類

3、onBind方法返回那個IBinder對象

在通信的Activity中,添加了一個名為ServiceConnection的類,並實現了onServiceConnected(從IBinder獲取Service對象)和onServiceDisconnected(set service to null)。

調用順序為:

bindService:

1、LoaclService:onCreate

2、LocalService:onBind

3、Activity:onServiceConnected

unbindService:

1、LocalService:onUnbind

2、Activity:onDestory

有個疑問:通過bindService啟動的服務,通過手機設置里面查看,並沒有一個運行的服務歸屬於主進程。而通過startService啟動的服務卻有一個運行的服務歸屬於主進程。求大神解釋下。

點擊下載Demo

二、RemoteService(遠程服務)

 

之前所談的Service屬於Local Service,即Service和Client在同一進程內(即同一application內),Service的生命周期服從進程的生命周期。在實際 應用上,有時希望Service作為后台服務,不僅被同一進程內的activity使用,也可被其他進程所使用,針對這種情況,需要采用 bindService,也就是Remote Service的方式。

 

在Android中,不同app屬不同進程 (process),進程是安全策略的邊界,一個進程不能訪問其他進程的存儲(例如采用ContentProvider)。在Remote Service中將涉及進程間通信,也就是通常講的IPC(interprocess commnication),需要在進程A和進程B之間建立連接,以便進行相互的通信或數據傳遞 。

Android提供AIDL(Android Interface Definition Language)工具幫助IPC之間接口的建立,大大地簡化了開發者視圖。右示意圖僅用於幫助理解代碼。通過下面的步驟實現client和service之間的通信:

 

【1】定義AIDL接口 ,Eclipse將自動為Service建立接口IService
【2】Client連接Service,連接到IService暴露給Client的Stub,獲得stub對象;換句話,Service通過接口中的Stub向client提供服務,在IService中對抽象IService.Stub具體實現。 
【3】Client和Service連接后,Client可向使用本地方法那樣,簡單地直接調用IService.Stub里面的方法。

 

遠程服務為獨立進程。

客戶端 通過AIDL方式建立一個到服務對象的連接,並通過那個連接來調用服務。連接以調用Context.bindService()方法建立,以調用 Context.unbindService()方法關閉。其實這個調用和那個本地服務中需要與Activity交互的方式是一樣的。同時多個客戶端可以 綁定到同一個服務。

AIDL使用步驟(這里的做法是服務端和客戶端分開的形式,貌似也可以服務端客戶端寫在一個應用中。需要在AndroidManifest.xml的service標簽中配置android:process):

1、首先創建服務端項目,創建一個AIDL文件,AIDL文件使用的包名建議與Package所指定的包名相同。

2、將AIDL文件添加到Package所指定的包下面,Android Eclipse插件將調用AIDL編譯器來從AIDL文件生成java接口。

3、實現一個服務並從onBind方法返回生成的接口

4、將服務配置到添加到AndroidManifest.xml文件中

注意一下:客戶端和服務端的AIDL文件內容必須一樣,通常做法是把服務端的寫好后直接復制到客戶端,以保證完全一樣。

尤其要注意的是:<action>標簽中android:name的屬性值就是客戶端要引用改服務的ID,也就是Intent類的參數值

 

點擊下載Demo 服務端   客戶端



最后對Service里面onStartCommand方法返回值進行下說明:

onStartCommand方法必須返回一個整數,這個整數是一個描述了在系統的殺死事件中,系統應該如何繼續這個服務的值,從onStartCommand返回的值必須是一下常量:

START_NOT_STICKY:如果系統在onStartCommand方法返回之后殺死這個服務,那個直到接收新的intent對象,這個服務才會被重新創建。這是最安全的選項,用來避免在不需要的時候運行你的服務。

START_STICKY: 如果系統在onStartCommand返回后殺死這個服務,系統就會重新創建這個服務並且調用onStartCommand方法,但是它不會重新傳遞最 后的Intent對象,系統會用一個null的intent對象來調用onStartCommand方法,在這個情況下,除非有一些被發送的Intent 對象在等待啟動服務。這適合於不執行命令的媒體播放器(或類似服務),它只是無限期的運行着並等待工作結束。

START_REDELIVER_INTENT: 如果系統在onStartCommand方法返回后,系統就會重新創建了這個服務,並且用發送給這個服務的最后的Intent對象調用了 onStartCommand方法。任意等待中的Intent對象會依次被發送。這適用於那些應該立即恢復正在執行的工作服務,比如下載等。

 

參考:http://android.blog.51cto.com/268543/527314/

http://www.cnblogs.com/linlf03/p/3296323.html

http://www.cnblogs.com/macroxu-1982/archive/2012/12/18/2823183.html

http://codingnow.cn/android/515.html

http://byandby.iteye.com/blog/1026193


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM