第7章后臺服務(wù).ppt_第1頁
第7章后臺服務(wù).ppt_第2頁
第7章后臺服務(wù).ppt_第3頁
第7章后臺服務(wù).ppt_第4頁
第7章后臺服務(wù).ppt_第5頁
已閱讀5頁,還剩112頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第七講 后臺服務(wù),本章學(xué)習(xí)目標(biāo),了解Service的原理和用途 掌握進(jìn)程內(nèi)服務(wù)的管理方法 掌握服務(wù)的隱式啟動和顯式啟動方法 了解線程的啟動、掛起和停止方法 了解跨線程的界面更新方法 掌握跨進(jìn)程服務(wù)的綁定和調(diào)用方法 了解AIDL語言的用途和語法,7.1 Service簡介,Service Service是Android系統(tǒng)的后臺服務(wù)組件,適用于開發(fā)無界面、長時(shí)間運(yùn)行的應(yīng)用功能 特點(diǎn) 沒有用戶界面 比Activity 的優(yōu)先級高,不會輕易被Android系統(tǒng)終止 即使Service被系統(tǒng)終止,在系統(tǒng)資源恢復(fù)后Service也將自動恢復(fù)運(yùn)行狀態(tài) 用于進(jìn)程間通信(Inter Process Commu

2、nication,IPC),解決兩個(gè)不同Android應(yīng)用程序進(jìn)程之間的調(diào)用和通訊問題,7.1 Service簡介,Service生命周期 Service生命周期包括 全生命周期 活動生命周期 onCreate()事件回調(diào)函數(shù): Service的生命周期開始,完成Service的初始化工作 onStart()事件回調(diào)函數(shù):活動生命周期開始,但沒有與之對應(yīng)的“停止”函數(shù),因此可以近似認(rèn)為活動生命周期也是以onDestroy()標(biāo)志結(jié)束 onDestroy()事件回調(diào)函數(shù): Service的生命周期結(jié)束,釋放Service所有占用的資源,7.1 Service簡介,Service使用方法 啟動方式

3、 綁定方式 啟動方式 通過調(diào)用Context.startService()啟動Service,通過調(diào)用Context.stopService()或Service.stopSefl()停止Service Service是由其他的組件啟動的,但停止過程可以通過其他組件或自身完成 如果僅以啟動方式使用的Service,這個(gè)Service需要具備自管理的能力,且不需要通過函數(shù)調(diào)用向外部組件提供數(shù)據(jù)或功能,7.1 Service簡介,綁定方式 通過服務(wù)鏈接(Connection)或直接獲取Service中狀態(tài)和數(shù)據(jù)信息 服務(wù)鏈接能夠獲取Service的對象,因此綁定Service的組件可以調(diào)用Servi

4、ce中的實(shí)現(xiàn)的函數(shù) 使用Service的組件通過Context.bindService()建立服務(wù)鏈接,通過Context.unbindService()停止服務(wù)鏈接 如果在綁定過程中Service沒有啟動,Context.bindService()會自動啟動Service 同一個(gè)Service可以綁定多個(gè)服務(wù)鏈接,這樣可以同時(shí)為多個(gè)不同的組件提供服務(wù),7.1 Service簡介,啟動方式和綁定方式的結(jié)合 這兩種使用方法并不是完全獨(dú)立的,在某些情況下可以混合使用 以MP3播放器為例,在后臺的工作的Service通過Context.startService()啟動某個(gè)特定音樂播放,但在播放過程中

5、如果用戶需要暫停音樂播放,則需要通過Context.bindService()獲取服務(wù)鏈接和Service對象,進(jìn)而通過調(diào)用Service的對象中的函數(shù),暫停音樂播放過程,并保存相關(guān)信息。在這種情況下,如果調(diào)用Context.stopService()并不能夠停止Service,需要在所有的服務(wù)鏈接關(guān)閉后,Service才能夠真正的停止,7.2 本地服務(wù),7.2.1 服務(wù)管理 服務(wù)管理主要指服務(wù)的啟動和停止 首先介紹實(shí)現(xiàn)Service的最小代碼集 第1行到第3行引入必要包 第5行聲明了RandomService繼承android.app.Service類 在第7行到第9行重載了onBind()

6、函數(shù),7.2 本地服務(wù),7.2.1 服務(wù)管理 onBind()函數(shù)是在Service被綁定后調(diào)用的函數(shù),能夠返回Service的對象,在后面的內(nèi)容中會詳細(xì)介紹 Service的最小代碼集并不能完成任何實(shí)際的功能,需要重載onCreate()、onStart()和onDestroy(),才使Service具有實(shí)際意義 Android系統(tǒng)在創(chuàng)建Service時(shí),會自動調(diào)用onCreate() 完成必要的初始化工作 在Service沒有必要再存在時(shí),系統(tǒng)會自動調(diào)用onDestroy(),釋放所有占用的資源 通過Context.startService(Intent)啟動Service時(shí),onStar

7、t()則會被系統(tǒng)調(diào)用,Intent會傳遞給Service一些重要的參數(shù) Service會根據(jù)實(shí)際情況選擇需要重載上面的三個(gè)函數(shù),7.2 本地服務(wù),7.2.1 服務(wù)管理 第4行、第8行和第12行的代碼重載onCreate()、onStart()和onDestroy()三個(gè)函數(shù)時(shí),必須要在代碼中調(diào)用父函數(shù),7.2 本地服務(wù),7.2.1 服務(wù)管理 注冊Service 在AndroidManifest.xml文件中注冊,否則,這個(gè)Service根本無法啟動 AndroidManifest.xml文件中注冊Service的代碼如下 使用標(biāo)簽聲明服務(wù),其中的android:name表示的是Service的

8、類名稱,一定要與用戶建立的Service類名稱一致,7.2 本地服務(wù),7.2.1 服務(wù)管理 啟動Service 啟動方式 顯示啟動 隱式啟動 顯示啟動:在Intent中指明Service所在的類,并調(diào)用startService(Intent)函數(shù)啟動Service,示例代碼如下 在Intent中指明啟動的Service在RandomSerevice.class中,7.2 本地服務(wù),7.2.1 服務(wù)管理 啟動Service 隱式啟動:在注冊Service時(shí),聲明Intent-filter的action屬性 設(shè)置Intent的action屬性,可以在不聲明Service所在類的情況下啟動服務(wù) 隱式

9、啟動的代碼如下,7.2 本地服務(wù),7.2.1 服務(wù)管理 啟動Service 若Service和調(diào)用服務(wù)的組件在同一個(gè)應(yīng)用程序中,可以使用顯式啟動或隱式啟動,顯式啟動更加易于使用,且代碼簡潔 若服務(wù)和調(diào)用服務(wù)的組件在不同的應(yīng)用程序中,則只能使用隱式啟動,7.2 本地服務(wù),7.2.1 服務(wù)管理 停止Service 將啟動Service的Intent傳遞給stopService(Intent)函數(shù)即可,示例代碼如下 在調(diào)用startService(Intent)函數(shù)首次啟動Service后,系統(tǒng)會先后調(diào)用onCreate()和onStart() 再次調(diào)用startService(Intent)函數(shù),

10、系統(tǒng)則僅調(diào)用onStart(),而不再調(diào)用onCreate() 在調(diào)用stopService(Intent)函數(shù)停止Service時(shí),系統(tǒng)會調(diào)用onDestroy() 無論調(diào)用過多少次startService(Intent),在調(diào)用stopService (Intent)函數(shù)時(shí),系統(tǒng)僅調(diào)用onDestroy()一次,7.2 本地服務(wù),7.2.1 服務(wù)管理 示例SimpleRandomServiceDemo以顯式啟動服務(wù)在應(yīng)用程序中建立Service 在工程中創(chuàng)建RandomService服務(wù),該服務(wù)啟動后會產(chǎn)生一個(gè)隨機(jī)數(shù),使用Toast顯示在屏幕上 “啟動Service”按鈕調(diào)用startSe

11、rvice(Intent)函數(shù),啟動RandomService服務(wù) “停止Service”按鈕調(diào)用stopService(Intent)函數(shù),停止RandomService服務(wù),7.2 本地服務(wù),7.2.1 服務(wù)管理 RandomService.java文件的代碼如下,7.2 本地服務(wù),7.2.1 服務(wù)管理,7.2 本地服務(wù),7.2.1 服務(wù)管理 在onStart()函數(shù)中添加生產(chǎn)隨機(jī)數(shù)的代碼,第23行生產(chǎn)一個(gè)介于0和1之間的隨機(jī)數(shù) 第24行代碼構(gòu)造供Toast顯示的消息,7.2 本地服務(wù),7.2.1 服務(wù)管理 AndroidManifest.xml文件的代碼如下,7.2 本地服務(wù),7.2.1

12、 服務(wù)管理 在調(diào)用AndroidManifest.xml文件中,在標(biāo)簽下,包含一個(gè)標(biāo)簽和一個(gè)標(biāo)簽,在標(biāo)簽中,聲明了RandomService所在的類,7.2 本地服務(wù),7.2.1 服務(wù)管理 SimpleRandomServiceDemo.java文件的代碼如下,7.2 本地服務(wù),7.2.1 服務(wù)管理 第20行和第25行分別是啟動和停止Service的代碼,7.2 本地服務(wù),7.2.2 使用線程 任何耗時(shí)的處理過程都會降低用戶界面的響應(yīng)速度,甚至導(dǎo)致用戶界面失去響應(yīng),當(dāng)用戶界面失去響應(yīng)超過5秒鐘,Android系統(tǒng)會允許用戶強(qiáng)行關(guān)閉應(yīng)用程序 較好的解決方法是將耗時(shí)的處理過程轉(zhuǎn)移到子線程上,這樣可

13、以避免負(fù)責(zé)界面更新的主線程無法處理界面事件,從而避免用戶界面長時(shí)間失去響應(yīng),7.2 本地服務(wù),7.2.2 使用線程 線程是獨(dú)立的程序單元,多個(gè)線程可以并行工作 在多處理器系統(tǒng)中,每個(gè)中央處理器(CPU)單獨(dú)運(yùn)行一個(gè)線程,因此線程是并行工作的 在單處理器系統(tǒng)中,處理器會給每個(gè)線程一小段時(shí)間,在這個(gè)時(shí)間內(nèi)線程是被執(zhí)行的,然后處理器執(zhí)行下一個(gè)線程,這樣就產(chǎn)生了線程并行運(yùn)行的假象 無論線程是否真的并行工作,在宏觀上可以認(rèn)為子線程是獨(dú)立于主線程,且能與主線程并行工作的程序單元,7.2 本地服務(wù),7.2.2 使用線程 使用線程 實(shí)現(xiàn)Java的Runnable接口,并重載run()方法。在run()中放置代

14、碼的主體部分,7.2 本地服務(wù),7.2.2 使用線程 使用線程 創(chuàng)建Thread對象,并將上面實(shí)現(xiàn)的Runnable對象作為參數(shù)傳遞給Thread對象 Thread的構(gòu)造函數(shù)中,第1個(gè)參數(shù)用來表示線程組 第2個(gè)參數(shù)是需要執(zhí)行的Runnable對象 第3個(gè)參數(shù)是線程的名稱 調(diào)用start()方法啟動線程,7.2 本地服務(wù),7.2.2 使用線程 線程在run()方法返回后,線程就自動終止了;不推薦使用調(diào)用stop()方法在外部終止線程 最好的方法是通知線程自行終止,一般調(diào)用interrupt()方法通告線程準(zhǔn)備終止,線程會釋放它正在使用的資源,在完成所有的清理工作后自行關(guān)閉 interrupt()

15、方法并不能直接終止線程,僅是改變了線程內(nèi)部的一個(gè)布爾字段,run()方法能夠檢測到這個(gè)布爾字段,從而知道何時(shí)應(yīng)該釋放資源和終止線程 在run()方法的代碼,一般通過Terrupted()方法查詢線程是否被中斷,7.2 本地服務(wù),7.2.2 使用線程 下面的代碼是以1秒為間隔循環(huán)檢測斷線程是否被中斷 第4行代碼使線程休眠1000毫秒 當(dāng)線程在休眠過程中被中斷,則會產(chǎn)生InterruptedException 在中斷的線程上調(diào)用sleep()方法,同樣會產(chǎn)生InterruptedException,7.2 本地服務(wù),7.2.2 使用線程 Terrupted()方

16、法功能 判斷線程是否應(yīng)被中斷 通過捕獲InterruptedException判斷線程是否應(yīng)被中斷,并且在捕獲到InterruptedException后,安全終止線程,7.2 本地服務(wù),7.2.2 使用線程 使用Handler更新用戶界面 Handler允許將Runnable對象發(fā)送到線程的消息隊(duì)列中,每個(gè)Handler對象綁定到一個(gè)單獨(dú)的線程和消息隊(duì)列上 當(dāng)用戶建立一個(gè)新的Handler對象,通過post()方法將Runnable對象從后臺線程發(fā)送到GUI線程的消息隊(duì)列中,當(dāng)Runnable對象通過消息隊(duì)列后,這個(gè)Runnable對象將被運(yùn)行,7.2 本地服務(wù),7.2.2 使用線程 第1行

17、代碼建立了一個(gè)靜態(tài)的Handler對象,但這個(gè)對象是私有的,因此外部代碼并不能直接調(diào)用這個(gè)Handler對象,7.2 本地服務(wù),7.2.2 使用線程 第3行UpdateGUI()是公有的界面更新函數(shù),后臺線程通過調(diào)用該函數(shù),將后臺產(chǎn)生的數(shù)據(jù)refreshDouble傳遞到UpdateGUI()函數(shù)內(nèi)部,然后并直接調(diào)用post()方法,將第6行的創(chuàng)建的Runnable對象傳遞給界面線程(主線程)的消息隊(duì)列中 第7行到第10行代碼是Runnable對象中需要重載的run()函數(shù),一般將界面更新代碼放置在run()函數(shù)中,7.2 本地服務(wù),7.2.2 使用線程 示例ThreadRandomServi

18、ceDemo使用線程持續(xù)產(chǎn)生隨機(jī)數(shù) 點(diǎn)擊“啟動Service”后,將啟動后臺線程 點(diǎn)擊“停止Service”后,將關(guān)閉后臺線程 后臺線程每1秒鐘產(chǎn)生一個(gè)0到1之間的隨機(jī)數(shù),并通過Handler將產(chǎn)生的隨機(jī)數(shù)顯示在用戶界面上,7.2 本地服務(wù),7.2.2 使用線程 在ThreadRandomServiceDemo示例中,RandomService.java文件是描述Service的文件,用來創(chuàng)建線程、產(chǎn)生隨機(jī)數(shù)和調(diào)用界面更新函數(shù) RandomService.java文件的完整代碼如下,7.2 本地服務(wù),7.2.2 使用線程,7.2 本地服務(wù),7.2.2 使用線程,7.2 本地服務(wù),7.2.2 使

19、用線程,7.2 本地服務(wù),7.2.2 使用線程 ThreadRandomServiceDemo.java文件是界面的Activity文件,封裝Handler的界面更新函數(shù)就在這個(gè)文件中 ThreadRandomServiceDemo.java文件的完整代碼,7.2 本地服務(wù),7.2.2 使用線程,7.2 本地服務(wù),7.2.2 使用線程,7.2 本地服務(wù),7.2.2 使用線程,7.2 本地服務(wù),7.2.3 服務(wù)綁定 以綁定方式使用Service,能夠獲取到Service對象,不僅能夠正常啟動Service,而且能夠調(diào)用正在運(yùn)行中的Service實(shí)現(xiàn)的公有方法和屬性 為了使Service支持綁定,

20、需要在Service類中重載onBind()方法,并在onBind()方法中返回Service對象,示例代碼如下,7.2 本地服務(wù),7.2.3 服務(wù)綁定 當(dāng)Service被綁定時(shí),系統(tǒng)會調(diào)用onBind()函數(shù),通過onBind()函數(shù)的返回值,將Service對象返回給調(diào)用者,7.2 本地服務(wù),7.2.3 服務(wù)綁定 第11行代碼中可以看出,onBind()函數(shù)的返回值必須是符合IBinder接口,因此在代碼的第2行聲明一個(gè)接口變量mBinder,mBinder符合onBind()函數(shù)返回值的要求,因此將mBinder傳遞給調(diào)用者 IBinder是用于進(jìn)程內(nèi)部和進(jìn)程間過程調(diào)用的輕量級接口,定義

21、了與遠(yuǎn)程對象交互的抽象協(xié)議,使用時(shí)通過繼承Binder的方法實(shí)現(xiàn) 第4行代碼繼承Binder,LocalBinder是繼承Binder的一個(gè)內(nèi)部類 第5行代碼實(shí)現(xiàn)了getService()函數(shù),當(dāng)調(diào)用者獲取到mBinder后,通過調(diào)用getService()即可獲取到Service的對象,7.2 本地服務(wù),7.2.3 服務(wù)綁定 調(diào)用者通過bindService()函數(shù)綁定服務(wù) 并在第1個(gè)參數(shù)中將Intent傳遞給bindService()函數(shù),聲明需要啟動的Service 第3個(gè)參數(shù)Context.BIND_AUTO_CREATE表明只要綁定存在,就自動建立Service;同時(shí)也告知Andro

22、id系統(tǒng),這個(gè)Service的重要程度與調(diào)用者相同,除非考慮終止調(diào)用者,否則不要關(guān)閉這個(gè)Service,7.2 本地服務(wù),7.2.3 服務(wù)綁定 bindService()函數(shù)的第2個(gè)參數(shù)是ServiceConnnection 當(dāng)綁定成功后,系統(tǒng)將調(diào)用ServiceConnnection的onServiceConnected()方法 而當(dāng)綁定意外斷開后,系統(tǒng)將調(diào)用ServiceConnnection中的onServiceDisconnected方法 由上可知,以綁定方式使用Service,調(diào)用者需要聲明一個(gè)ServiceConnnection,并重載內(nèi)部的onServiceConnected()

23、方法和onServiceDisconnected方法,7.2 本地服務(wù),7.2.3 服務(wù)綁定 在第4行代碼中,綁定成功后通過getService()獲取Service對象,這樣便可以調(diào)用Service中的方法和屬性 第8行代碼將Service對象設(shè)置為null,表示綁定意外失效,Service實(shí)例不再可用,7.2 本地服務(wù),7.2.3 服務(wù)綁定 取消綁定僅需要使用unbindService()方法,并將ServiceConnnection傳遞給unbindService()方法 需注意的是,unbindService()方法成功后,系統(tǒng)并不會調(diào)用onServiceConnected(),因?yàn)閛

24、nServiceConnected()僅在意外斷開綁定時(shí)才被調(diào)用,7.2 本地服務(wù),7.2.3 服務(wù)綁定 通過bindService()函數(shù)綁定Servcie時(shí), onCreate()函數(shù)和onBinde()函數(shù)將先后被調(diào)用 通過unbindService()函數(shù)取消綁定Servcie時(shí),onUnbind()函數(shù)將被調(diào)用,如果onUnbind()函數(shù)的返回true,則表示在調(diào)用者綁定新服務(wù)時(shí),onRebind()函數(shù)將被調(diào)用 綁定方式的函數(shù)調(diào)用順序,7.2 本地服務(wù),7.2.3 服務(wù)綁定 示例SimpleMathServiceDemo使用綁定方式使用Service 創(chuàng)建了MathService

25、服務(wù),用來完成簡單的數(shù)學(xué)運(yùn)算但足以說明如何使用綁定方式調(diào)用Service實(shí)例中的公有方法,7.2 本地服務(wù),7.2.3 服務(wù)綁定 在服務(wù)綁定后,用戶可以點(diǎn)擊“加法運(yùn)算”,將兩個(gè)隨機(jī)產(chǎn)生的數(shù)值傳遞給MathService服務(wù),并從MathService對象中獲取到加法運(yùn)算的結(jié)果,然后顯示在屏幕的上方 “取消綁定”按鈕可以解除與MathService的綁定關(guān)系,取消綁定后,無法通過“加法運(yùn)算”按鈕獲取加法運(yùn)算結(jié)果,7.2 本地服務(wù),7.2.3 服務(wù)綁定 在SimpleMathServiceDemo示例中,MathService.java文件是描述Service的文件 MathService.jav

26、a文件的完整代碼如下,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.2 本地服務(wù),7.2.3 服務(wù)綁定 SimpleMathServiceDemo.java文件是界面的Activity文件,綁定和取消綁定服務(wù)的代碼在這個(gè)文件中 SimpleMathServiceDemo.java文件的完整代碼如下,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.2 本地服務(wù),7.2.3 服務(wù)綁定,7.3 遠(yuǎn)程服務(wù),7.3.1 進(jìn)程間通信 在Android系統(tǒng)中,每個(gè)應(yīng)用程序在各自的進(jìn)程中運(yùn)行,而且

27、出于安全原因的考慮,這些進(jìn)程之間彼此是隔離的,進(jìn)程之間傳遞數(shù)據(jù)和對象,需要使用Android支持的進(jìn)程間通信(Inter-Process Communication,IPC)機(jī)制 進(jìn)程間通信采用Intent和跨進(jìn)程服務(wù)的方式實(shí)現(xiàn)IPC,使應(yīng)用程序具有更好的獨(dú)立性和魯棒性 IPC機(jī)制包含 Intent:承載數(shù)據(jù),是一種簡單、高效、且易于使用的IPC機(jī)制 遠(yuǎn)程服務(wù):服務(wù)和調(diào)用者在不同的兩個(gè)進(jìn)程中,調(diào)用過程需要跨越進(jìn)程才能實(shí)現(xiàn),7.3 遠(yuǎn)程服務(wù),7.3.1 進(jìn)程間通信 實(shí)現(xiàn)遠(yuǎn)程服務(wù)的步驟 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 根據(jù)AIDL語言定義的接口,在具體的Service類中實(shí)現(xiàn)接口中定義的方法

28、和屬性 在需要調(diào)用跨進(jìn)程服務(wù)的組件中,通過相同的AIDL接口文件,調(diào)用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 AIDL(Android Interface Definition Language)是Android系統(tǒng)自定義的接口描述語言,可以簡化進(jìn)程間數(shù)據(jù)格式轉(zhuǎn)換和數(shù)據(jù)交換的代碼,通過定義Service內(nèi)部的公共方法,允許調(diào)用者和Service在不同進(jìn)程間相互傳遞數(shù)據(jù) AIDL的IPC機(jī)制與COM和Corba非常相似,都是基于接口的輕量級進(jìn)程通信機(jī)制 AIDL語言的語法與Java語言的接口定義非常相似,唯一不同之處是:AIDL允許定義函數(shù)參數(shù)的傳遞方向,7.3 遠(yuǎn)程服務(wù),7.

29、3.2 服務(wù)創(chuàng)建與調(diào)用 AIDL支持三種方向:in、out和inout 標(biāo)識為in的參數(shù)將從調(diào)用者傳遞到跨進(jìn)程服務(wù)中 標(biāo)識為out的參數(shù)將從跨進(jìn)程服務(wù)傳遞到調(diào)用者中 標(biāo)識為inout的參數(shù)將先從調(diào)用者傳遞到跨進(jìn)程服務(wù)中,再從跨進(jìn)程服務(wù)返回給調(diào)用者 在不標(biāo)識參數(shù)的傳遞方向時(shí),缺省認(rèn)定所有函數(shù)的傳遞方向?yàn)閕n 出于性能方面的考慮,不要在參數(shù)中標(biāo)識不需要的傳遞方向,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 遠(yuǎn)程訪問的創(chuàng)建和調(diào)用需要使用AIDL語言,一般分為以下幾個(gè)過程 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2

30、 服務(wù)創(chuàng)建與調(diào)用 下面以RemoteMathServiceDemo示例為參考,說明如何創(chuàng)建跨進(jìn)程服務(wù) 在這個(gè)示例中,僅定義了MathService服務(wù),可以為遠(yuǎn)程調(diào)用者提供加法服務(wù) 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 首先使用AIDL語言定義的MathService的服務(wù)接口,文件名為IMathService.aidl IMathService接口僅包含一個(gè)add()方法,傳入的參數(shù)是兩個(gè)長型整數(shù),返回值也是長型整數(shù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 如果使用Eclipse編輯IMathService.aidl文件,當(dāng)用戶保存文件后,ADT會

31、自動在/gen目錄下生成IMathService.java文件 右圖是IMathService.java文件結(jié)構(gòu),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 IMathService.java文件根據(jù)IMathService.aidl的定義,生成了一個(gè)內(nèi)部靜態(tài)抽象類Stub,Stub繼承了Binder類,并實(shí)現(xiàn)ImathService接口 在Stub類中,還包含一個(gè)重要的靜態(tài)類Proxy。如果認(rèn)為Stub類實(shí)現(xiàn)進(jìn)程內(nèi)服務(wù)調(diào)用,那么Proxy類則是用來實(shí)現(xiàn)跨進(jìn)程服務(wù)調(diào)用的,將Proxy作為Stub的內(nèi)部類完全是出于使用方便的目的,7.3 遠(yuǎn)程服務(wù),7.3.

32、2 服務(wù)創(chuàng)建與調(diào)用 使用AIDL語言定義跨進(jìn)程服務(wù)的接口 Stub類和Proxy類關(guān)系圖,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 IMathService.java的完整代碼,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 第8行代碼是IMathService繼承了android.os.IInterface,這是所有使用AIDL建立的接口都必須繼承的基類接口,這個(gè)基類接口中定義了asBinder()方法,用來

33、獲取Binder對象 在代碼的第30行到第32行,實(shí)現(xiàn)了android.os.IInterface接口所定義的asBinder()方法 在IMathService中,絕大多數(shù)的代碼是用來實(shí)現(xiàn)Stub這個(gè)抽象類的。每個(gè)遠(yuǎn)程接口都包Stub類,因?yàn)槭莾?nèi)部類,所有并不會產(chǎn)生命名的沖突 asInterface(IBinder)是Stub內(nèi)部的跨進(jìn)程服務(wù)接口,調(diào)用者可以通過該方法獲取到跨進(jìn)程服務(wù)的對象,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 仔細(xì)觀察asInterface(IBinder)實(shí)現(xiàn)方法,首先判斷IBinder對象obj是否為null(第21行),如果是則立即返回 第24行代碼是使用DE

34、SCRIPTOR構(gòu)造android.os.IInterface對象,并判斷android.os.IInterface對象是否為進(jìn)程內(nèi)服務(wù) 如果是進(jìn)程內(nèi)服務(wù),則無需進(jìn)程間通信,返回android.os.IInterface對象(第26行) 如果不是進(jìn)程內(nèi)服務(wù),則構(gòu)造并返回Proxy對象(第28行) 第66行代碼是Proxy內(nèi)部包含與IMathService.aidl相同簽名的函數(shù) 第7176行代碼是在該函數(shù)中以一定的順序?qū)⑺袇?shù)寫入Parcel對象,以供Stub內(nèi)部的onTransact()方法能夠正確獲取到參數(shù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 當(dāng)數(shù)據(jù)以Parcel對象的形式傳遞

35、到跨進(jìn)程服務(wù)的內(nèi)部時(shí),onTransact()方法(第33行)將從Parcel對象中逐一的讀取每個(gè)參數(shù),然后調(diào)用Service內(nèi)部制定的方法,并再將結(jié)果寫入另一個(gè)Parcel對象,準(zhǔn)備將這個(gè)Parcel對象返回給遠(yuǎn)程的調(diào)用者 Parcel是Android系統(tǒng)中應(yīng)用程序進(jìn)程間數(shù)據(jù)傳遞的容器,能夠在兩個(gè)進(jìn)程中完成數(shù)據(jù)的打包和拆包的工作,但Parcel不同于通用意義上的序列化,Parcel的設(shè)計(jì)目的是用于高性能IPC傳輸,因此不能夠?qū)arcel對象保存在任何持久存儲設(shè)備上,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 實(shí)現(xiàn)跨進(jìn)程服務(wù)需要建立一個(gè)繼承andro

36、id.app.Service的類,并在該類中通過onBind()方法返回IBinder對象,調(diào)用者使用返回的IBinder對象就可以訪問跨進(jìn)程服務(wù) IBinder對象的建立通過使用IMathService.java內(nèi)部的Stub類實(shí)現(xiàn),并逐一實(shí)現(xiàn)在IMathService.aidl接口文件定義的函數(shù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 在RemoteMathServiceDemo示例中,跨進(jìn)程服務(wù)的實(shí)現(xiàn)類是MathService.java 下面是MathService.java的完整代碼,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承S

37、ervice類實(shí)現(xiàn)跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 第8行代碼表明MathService繼承于android.app.Service 第9行代碼建立IMathService.Stub的對象mBinder 第10行代碼實(shí)現(xiàn)了AIDL文件定義的跨進(jìn)程服務(wù)接口 第18行代碼在onBind()方法中,將mBinder返回給遠(yuǎn)程調(diào)用者 第16行和第22行代碼分別是在綁定和取消綁定時(shí),為用戶產(chǎn)生的提示信息,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) RemoteMathServiceDemo示例的文件

38、結(jié)構(gòu)如圖 示例中只有跨進(jìn)程服務(wù)的類文件MathService.java和接口文件IMathService.aidl,沒有任何用于啟動時(shí)顯示用戶界面的Activity文件,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 在調(diào)試RemoteMathServiceDemo示例時(shí),模擬器的屏幕上不會出現(xiàn)用戶界面,但在控制臺會有“沒有找到用于啟動的Activity,僅將應(yīng)用程序同步到設(shè)備上”的提示信息,這些信息表明apk文件已經(jīng)上傳到模擬器中 提示信息如圖,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 使用File Explo

39、rer查看模擬器的文件系統(tǒng),可以進(jìn)一步確認(rèn)編譯好的apk文件是否正確上傳到模擬器中 如果能在/data/app/下找到edu.hrbeu.RemoteMathServiceDemo.apk文件,說明提供跨進(jìn)程服務(wù)的apk文件已經(jīng)正確上傳 如果RemoteMathServiceDemo示例無法在Android模擬器的程序啟動欄中找到,只能夠通過其他應(yīng)用程序調(diào)用該示例中的跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) 下圖表示edu.hrbeu.RemoteMathServiceDemo.apk文件的保存位置,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建

40、與調(diào)用 通過繼承Service類實(shí)現(xiàn)跨進(jìn)程服務(wù) RemoteMathServiceDemo是本書中第一個(gè)沒有Activity的示例,在AndroidManifest.xml文件中,在標(biāo)簽下只有一個(gè)標(biāo)簽 AndroidManifest.xml文件的完代碼如下,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 注意第10行代碼,edu.hrbeu.RemoteMathServiceDemo.MathService是遠(yuǎn)程調(diào)用MathService的標(biāo)識,在調(diào)用者段使用Intent.setAction()函數(shù)將標(biāo)識加入Intent中,然后隱式啟動或綁定服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁

41、定和使用跨進(jìn)程服務(wù) 下圖是RemoteMathCallerDemo的界面 用戶可以綁定跨進(jìn)程服務(wù),也可以取消服務(wù)綁定 在綁定跨進(jìn)程服務(wù)后,可以調(diào)用RemoteMathServiceDemo中的MathService服務(wù)進(jìn)行加法運(yùn)算,運(yùn)算的輸入由RemoteMathCallerDemo隨機(jī)產(chǎn)生,運(yùn)算的輸入和結(jié)果顯示在屏幕的上方,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù) 應(yīng)用程序在調(diào)用跨進(jìn)程服務(wù)時(shí),應(yīng)用程序與跨進(jìn)程服務(wù)應(yīng)具有相同的Proxy類和簽名函數(shù),這樣才能夠使數(shù)據(jù)在調(diào)用者處打包后,可以在遠(yuǎn)程訪問端正確拆包,反之亦然 從實(shí)踐角度來講,調(diào)用者需要使用與跨進(jìn)程服務(wù)端相同的

42、AIDL文件 在RemoteMathCallerDemo示例,在edu.hrbeu.RemoteMathServiceDemo包下,引如與RemoteMathServiceDemo相同的AIDL文件IMathService.aidl,同時(shí)在/gen目錄下會自動產(chǎn)生相同的IMathService.java文件,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù) 下圖是RemoteMathServiceDemo的文件結(jié)構(gòu),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù) RemoteMathCallerDemo.java是Activity的文件,跨進(jìn)程服務(wù)的綁定和

43、使用方法與7.2.3節(jié)的進(jìn)程內(nèi)服務(wù)綁定示例SimpleMathServiceDemo相似 不同之處主要包括以下兩個(gè)方面 第1行代碼使用IMathService聲明跨進(jìn)程服務(wù)對象 第6行代碼通過IMathService.Stub的asInterface()方法實(shí)現(xiàn)獲取服務(wù)對象,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù) 綁定服務(wù)時(shí),首先通過setAction()方法聲明服務(wù)標(biāo)識,然后調(diào)用bindService()綁定服務(wù) 服務(wù)標(biāo)識必須與跨進(jìn)程服務(wù)在AndroidManifest.xml文件中聲明的服務(wù)標(biāo)識

44、完全相同。因此本示例的服務(wù)標(biāo)識為edu.hrbeu.RemoteMathServiceDemo.MathService,與跨進(jìn)程服務(wù)示例RemoteMathServiceDemo在AndroidManifest.xml文件聲明的服務(wù)標(biāo)識一致,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù) 下面是RemoteMathCallerDemo.java文件的完整代碼,7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服

45、務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.2 服務(wù)創(chuàng)建與調(diào)用 綁定和使用跨進(jìn)程服務(wù),7.3 遠(yuǎn)程服務(wù),7.3.3 數(shù)據(jù)傳遞 在Android系統(tǒng)中,進(jìn)程間傳遞的數(shù)據(jù)包括: Java語言支持的基本數(shù)據(jù)類型 用戶自定義的數(shù)據(jù)類型 所有數(shù)據(jù)都必須是“可打包”的,才能夠穿越進(jìn)程邊界 Java語言的基本數(shù)據(jù)類型的打包過程是自動完成 對于自定義的數(shù)據(jù)類型,則需要實(shí)現(xiàn)Parcelable接口,使自定義的數(shù)據(jù)類型能夠轉(zhuǎn)換為系統(tǒng)級原語保存在Parcel對象中,穿越進(jìn)程邊界后可再轉(zhuǎn)換為初始格式,7.3 遠(yuǎn)程服務(wù),7.3.3 數(shù)據(jù)傳遞 AIDL支持的數(shù)據(jù)類型表,7.3 遠(yuǎn)程服務(wù),7.3.3 數(shù)據(jù)傳遞 下面以ParcelMathServiceDemo示例為參考,說明如何在跨進(jìn)程服務(wù)中使用自定義數(shù)據(jù)類型 這個(gè)示例是RemoteMathServiceDemo示例的延續(xù) 定義MathService服務(wù),為遠(yuǎn)程調(diào)用者提供加法服務(wù),沒有啟動界面,因此在模擬器的調(diào)試過程與RemoteMathServiceDemo示例相同 不同之處在于MathService服務(wù)增加了“全運(yùn)算”功能 在接收到輸入?yún)?shù)后,將向調(diào)用者返回一個(gè)包含“加、減、乘、除”全部運(yùn)算結(jié)果的對象。這個(gè)對象是一個(gè)自定義的類,為了能夠使其他AIDL文件可使用這個(gè)自定義類,需要使用AIDL語言聲明

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論