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

下載本文檔

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

文檔簡介

第7章后臺服務(wù)本章學(xué)習(xí)目標(biāo)了解Service的原理和用途掌握進(jìn)程內(nèi)服務(wù)的管理方法掌握服務(wù)的隱式啟動和顯式啟動方法了解線程的啟動、掛起和停止方法了解跨線程的界面更新方法掌握跨進(jìn)程服務(wù)的綁定和調(diào)用方法了解AIDL語言的用途和語法

7.1

Service簡介ServiceService是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)程間通信(InterProcessCommunication,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使用方法啟動方式綁定方式啟動方式通過調(diào)用Context.startService()啟動Service,通過調(diào)用Context.stopService()或Service.stopSefl()停止ServiceService是由其他的組件啟動的,但停止過程可以通過其他組件或自身完成如果僅以啟動方式使用的Service,這個(gè)Service需要具備自管理的能力,且不需要通過函數(shù)調(diào)用向外部組件提供數(shù)據(jù)或功能7.1

Service簡介綁定方式通過服務(wù)鏈接(Connection)或直接獲取Service中狀態(tài)和數(shù)據(jù)信息服務(wù)鏈接能夠獲取Service的對象,因此綁定Service的組件可以調(diào)用Service中的實(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è)特定音樂播放,但在播放過程中如果用戶需要暫停音樂播放,則需要通過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()函數(shù)importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;

publicclassRandomServiceextendsService{ @Override publicIBinderonBind(Intentintent){ returnnull; }}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í),onStart()則會被系統(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ù)publicclassRandomServiceextendsService{ @Override publicvoidonCreate(){ super.onCreate(); } @Override publicvoidonStart(Intentintent,intstartId){ super.onStart(intent,startId); } @Override publicvoidonDestroy(){ super.onDestroy(); }}7.2本地服務(wù)7.2.1服務(wù)管理注冊Service在AndroidManifest.xml文件中注冊,否則,這個(gè)Service根本無法啟動AndroidManifest.xml文件中注冊Service的代碼如下使用<service>標(biāo)簽聲明服務(wù),其中的android:name表示的是Service的類名稱,一定要與用戶建立的Service類名稱一致<serviceandroid:name=".RandomService"/>7.2本地服務(wù)7.2.1服務(wù)管理啟動Service啟動方式顯示啟動隱式啟動顯示啟動:在Intent中指明Service所在的類,并調(diào)用startService(Intent)函數(shù)啟動Service,示例代碼如下在Intent中指明啟動的Service在RandomSerevice.class中finalIntentserviceIntent=newIntent(this,RandomService.class);startService(serviceIntent);7.2本地服務(wù)7.2.1服務(wù)管理啟動Service隱式啟動:在注冊Service時(shí),聲明Intent-filter的action屬性設(shè)置Intent的action屬性,可以在不聲明Service所在類的情況下啟動服務(wù)隱式啟動的代碼如下<serviceandroid:name=".RandomService"> <intent-filter> <actionandroid:name="edu.hrbeu.RandomService"/> </intent-filter></service>finalIntentserviceIntent=newIntent();serviceIntent.setAction("edu.hrbeu.RandomService");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ù),系統(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()一次stopService(serviceIntent);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)用startService(Intent)函數(shù),啟動RandomService服務(wù)“停止Service”按鈕調(diào)用stopService(Intent)函數(shù),停止RandomService服務(wù)7.2本地服務(wù)7.2.1服務(wù)管理RandomService.java文件的代碼如下packageedu.hrbeu.SimpleRandomServiceDemo;

importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;importandroid.widget.Toast;

publicclassRandomServiceextendsService{

@Override publicvoidonCreate(){ super.onCreate(); Toast.makeText(this,"(1)調(diào)用onCreate()", Toast.LENGTH_LONG).show(); }

7.2本地服務(wù)7.2.1服務(wù)管理17. @Override18. publicvoidonStart(Intentintent,intstartId){19. super.onStart(intent,startId);20. Toast.makeText(this,"(2)調(diào)用onStart()",Toast.LENGTH_SHORT).show();

23. doublerandomDouble=Math.random();24. Stringmsg="隨機(jī)數(shù):"+String.valueOf(randomDouble);25. Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();26. }27. 28. @Override29. publicvoidonDestroy(){30. super.onDestroy();31. Toast.makeText(this,"(3)調(diào)用onDestroy()",32. Toast.LENGTH_SHORT).show();33. }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顯示的消息34. 35. @Override36. publicIBinderonBind(Intentintent){37. returnnull;38. }39.}7.2本地服務(wù)7.2.1服務(wù)管理AndroidManifest.xml文件的代碼如下<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res/android"package="edu.hrbeu.SimpleRandomServiceDemo"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"

android:label="@string/app_name"><activityandroid:name=".SimpleRandomServiceDemo"android:label="@string/app_name"><intent-filter><actionandroid:name="ent.action.MAIN"/><categoryandroid:name="ent.category.LAUNCHER"/></intent-filter></activity>7.2本地服務(wù)7.2.1服務(wù)管理在調(diào)用AndroidManifest.xml文件中,在<application>標(biāo)簽下,包含一個(gè)<activity>標(biāo)簽和一個(gè)<service>標(biāo)簽,在<service>標(biāo)簽中,聲明了RandomService所在的類14.<serviceandroid:name=".RandomService"/>15. </application>16.<uses-sdkandroid:minSdkVersion="3"/>17.</manifest>7.2本地服務(wù)7.2.1服務(wù)管理SimpleRandomServiceDemo.java文件的代碼如下packageedu.hrbeu.SimpleRandomServiceDemo;

importandroid.app.Activity;importandroid.content.Intent;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.Button;

publicclassSimpleRandomServiceDemoextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main);

7.2本地服務(wù)7.2.1服務(wù)管理第20行和第25行分別是啟動和停止Service的代碼15.

ButtonstartButton=(Button)findViewById(R.id.start);16. ButtonstopButton=(Button)findViewById(R.id.stop);17. finalIntentserviceIntent=newIntent(this,RandomService.class);18. startButton.setOnClickListener(newButton.OnClickListener(){19. publicvoidonClick(Viewview){20. startService(serviceIntent);21. }22. });23. stopButton.setOnClickListener(newButton.OnClickListener(){24. publicvoidonClick(Viewview){25. stopService(serviceIntent);26. }27. });28. }29.}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)移到子線程上,這樣可以避免負(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()中放置代碼的主體部分privateRunnablebackgroudWork=newRunnable(){ @Override publicvoidrun(){ //過程代碼

} };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()方法啟動線程privateThreadworkThread;workThread=newThread(null,backgroudWork,"WorkThread");workThread.start();7.2本地服務(wù)7.2.2使用線程線程在run()方法返回后,線程就自動終止了;不推薦使用調(diào)用stop()方法在外部終止線程最好的方法是通知線程自行終止,一般調(diào)用interrupt()方法通告線程準(zhǔn)備終止,線程會釋放它正在使用的資源,在完成所有的清理工作后自行關(guān)閉interrupt()方法并不能直接終止線程,僅是改變了線程內(nèi)部的一個(gè)布爾字段,run()方法能夠檢測到這個(gè)布爾字段,從而知道何時(shí)應(yīng)該釋放資源和終止線程在run()方法的代碼,一般通過Terrupted()方法查詢線程是否被中斷workTerrupt();7.2本地服務(wù)7.2.2使用線程下面的代碼是以1秒為間隔循環(huán)檢測斷線程是否被中斷第4行代碼使線程休眠1000毫秒當(dāng)線程在休眠過程中被中斷,則會產(chǎn)生InterruptedException在中斷的線程上調(diào)用sleep()方法,同樣會產(chǎn)生InterruptedExceptionpublicvoidrun(){ while(!Terrupted()){ //過程代碼

Thread.sleep(1000); }}7.2本地服務(wù)7.2.2使用線程Terrupted()方法功能判斷線程是否應(yīng)被中斷通過捕獲InterruptedException判斷線程是否應(yīng)被中斷,并且在捕獲到InterruptedException后,安全終止線程publicvoidrun(){ try{ while(true){ //過程代碼

Thread.sleep(1000); } }catch(InterruptedExceptione){ e.printStackTrace(); }}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行代碼建立了一個(gè)靜態(tài)的Handler對象,但這個(gè)對象是私有的,因此外部代碼并不能直接調(diào)用這個(gè)Handler對象privatestaticHandlerhandler=newHandler();

publicstaticvoidUpdateGUI(doublerefreshDouble){ handler.post(RefreshLable);}privatestaticRunnableRefreshLable=newRunnable(){ @Override publicvoidrun(){ //過程代碼

}};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使用線程示例ThreadRandomServiceDemo使用線程持續(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文件的完整代碼如下packageedu.hrbeu.ThreadRandomServiceDemo;

importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;importandroid.widget.Toast;

publicclassRandomServiceextendsService{

privateThreadworkThread;

7.2本地服務(wù)7.2.2使用線程12.

@Override13. publicvoidonCreate(){14. super.onCreate();15. Toast.makeText(this,"(1)調(diào)用onCreate()",16. Toast.LENGTH_LONG).show();17. workThread=newThread(null,backgroudWork,"WorkThread");18. }19. 20. @Override21. publicvoidonStart(Intentintent,intstartId){22. super.onStart(intent,startId);23. Toast.makeText(this,"(2)調(diào)用onStart()",24. Toast.LENGTH_SHORT).show();25. if(!workThread.isAlive()){26. workThread.start();27. }28. }29. 7.2本地服務(wù)7.2.2使用線程30.

@Override31. publicvoidonDestroy(){32. super.onDestroy();33. Toast.makeText(this,"(3)調(diào)用onDestroy()",34. Toast.LENGTH_SHORT).show();35. workTerrupt();36. }37. 38. @Override39. publicIBinderonBind(Intentintent){40. returnnull;41. }42. 7.2本地服務(wù)7.2.2使用線程43.

privateRunnablebackgroudWork=newRunnable(){44. @Override45. publicvoidrun(){46. try{47. while(!Terrupted()){ 48. doublerandomDouble=Math.random();49. ThreadRandomServiceDemo.UpdateGUI(randomDouble);50. Thread.sleep(1000);51. }52. }catch(InterruptedExceptione){53. e.printStackTrace();54. }55. }56. };57.}7.2本地服務(wù)7.2.2使用線程ThreadRandomServiceDemo.java文件是界面的Activity文件,封裝Handler的界面更新函數(shù)就在這個(gè)文件中ThreadRandomServiceDemo.java文件的完整代碼packageedu.hrbeu.ThreadRandomServiceDemo;

importandroid.app.Activity;importandroid.content.Intent;importandroid.os.Bundle;importandroid.os.Handler;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TextView;

7.2本地服務(wù)7.2.2使用線程11.publicclassThreadRandomServiceDemoextendsActivity{12.13. privatestaticHandlerhandler=newHandler();14.privatestaticTextViewlabelView=null; privatestaticdoublerandomDouble;16. 17. publicstaticvoidUpdateGUI(doublerefreshDouble){ randomDouble=refreshDouble;19. handler.post(RefreshLable);20. }21. 22. privatestaticRunnableRefreshLable=newRunnable(){23. @Override24. publicvoidrun(){25. labelView.setText(String.valueOf(randomDouble));26. }27. };28. 7.2本地服務(wù)7.2.2使用線程29.

@Override30. publicvoidonCreate(BundlesavedInstanceState){31. super.onCreate(savedInstanceState);32. setContentView(R.layout.main);33. labelView=(TextView)findViewById(R.id.label);34. ButtonstartButton=(Button)findViewById(R.id.start);35. ButtonstopButton=(Button)findViewById(R.id.stop);36. finalIntentserviceIntent=newIntent(this,RandomService.class);37.38. startButton.setOnClickListener(newButton.OnClickListener(){39. publicvoidonClick(Viewview){40. startService(serviceIntent);41. }42. });43.7.2本地服務(wù)7.2.2使用線程44.

stopButton.setOnClickListener(newButton.OnClickListener(){45. publicvoidonClick(Viewview){46. stopService(serviceIntent);47. }48. });49. }50.}7.2本地服務(wù)7.2.3

服務(wù)綁定以綁定方式使用Service,能夠獲取到Service對象,不僅能夠正常啟動Service,而且能夠調(diào)用正在運(yùn)行中的Service實(shí)現(xiàn)的公有方法和屬性為了使Service支持綁定,需要在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)用者publicclassMathServiceextendsService{ privatefinalIBindermBinder=newLocalBinder();

publicclassLocalBinderextendsBinder{ MathServicegetService(){ returnMathService.this; } }

@Override publicIBinderonBind(Intentintent){ returnmBinder; }}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)用的輕量級接口,定義了與遠(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í)也告知Android系統(tǒng),這個(gè)Service的重要程度與調(diào)用者相同,除非考慮終止調(diào)用者,否則不要關(guān)閉這個(gè)ServicefinalIntentserviceIntent=newIntent(this,MathService.class);bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE);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()方法和onServiceDisconnected方法7.2本地服務(wù)7.2.3

服務(wù)綁定在第4行代碼中,綁定成功后通過getService()獲取Service對象,這樣便可以調(diào)用Service中的方法和屬性第8行代碼將Service對象設(shè)置為null,表示綁定意外失效,Service實(shí)例不再可用privateServiceConnectionmConnection=newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice){ mathService=((MathService.LocalBinder)service).getService(); } @Override publicvoidonServiceDisconnected(ComponentNamename){ mathService=null; }};7.2本地服務(wù)7.2.3

服務(wù)綁定取消綁定僅需要使用unbindService()方法,并將ServiceConnnection傳遞給unbindService()方法需注意的是,unbindService()方法成功后,系統(tǒng)并不會調(diào)用onServiceConnected(),因?yàn)閛nServiceConnected()僅在意外斷開綁定時(shí)才被調(diào)用unbindService(mConnection);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服務(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.java文件的完整代碼如下packageedu.hrbeu.SimpleMathServiceDemo;

importandroid.app.Service;importandroid.content.Intent;importandroid.os.Binder;importandroid.os.IBinder;importandroid.widget.Toast;

publicclassMathServiceextendsService{

7.2本地服務(wù)7.2.3

服務(wù)綁定privatefinalIBindermBinder=newLocalBinder();

13. publicclassLocalBinderextendsBinder{14. MathServicegetService(){15. returnMathService.this;16. }}

19. @Override20. publicIBinderonBind(Intentintent){21. Toast.makeText(this,"本地綁定:MathService",22. Toast.LENGTH_SHORT).show();23. returnmBinder;24. }25. 7.2本地服務(wù)7.2.3

服務(wù)綁定26.

@Override27. publicbooleanonUnbind(Intentintent){28. Toast.makeText(this,"取消本地綁定:MathService",29. Toast.LENGTH_SHORT).show();30. returnfalse;31. }32.33. 34. publiclongAdd(longa,longb){35. returna+b;36. }37. 38.}7.2本地服務(wù)7.2.3

服務(wù)綁定SimpleMathServiceDemo.java文件是界面的Activity文件,綁定和取消綁定服務(wù)的代碼在這個(gè)文件中SimpleMathServiceDemo.java文件的完整代碼如下packageedu.hrbeu.SimpleMathServiceDemo;

importandroid.app.Activity;importandroid.content.ComponentName;importandroid.content.Context;importandroid.content.Intent;importandroid.content.ServiceConnection;importandroid.os.Bundle;importandroid.os.IBinder;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TextView;

7.2本地服務(wù)7.2.3

服務(wù)綁定14.publicclassSimpleMathServiceDemoextendsActivity{15. privateMathServicemathService;16. privatebooleanisBound=false;17. TextViewlabelView;18.@Override19.publicvoidonCreate(BundlesavedInstanceState){20.super.onCreate(savedInstanceState);21.setContentView(R.layout.main);22.23.labelView=(TextView)findViewById(R.id.label);24.ButtonbindButton=(Button)findViewById(R.id.bind);25.ButtonunbindButton=(Button)findViewById(R.id.unbind);26.ButtoncomputButton=(Button)findViewById(R.pute);27.28.bindButton.setOnClickListener(newView.OnClickListener(){29. @Override30. publicvoidonClick(Viewv){31. if(!isBound){7.2本地服務(wù)7.2.3

服務(wù)綁定32. finalIntentserviceIntent=newIntent(SimpleMathServiceDemo.this,MathService.class);33. bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE);34. isBound=true;35. }36. } });

39..unbindButton.setOnClickListener(newView.OnClickListener(){40. @Override41. publicvoidonClick(Viewv){42. if(isBound){43. isBound=false;44.unbindService(mConnection);45. mathService=null;46. }47. } 48.});7.2本地服務(wù)7.2.3

服務(wù)綁定49.50.computButton.setOnClickListener(newView.OnClickListener(){51. @Override52. publicvoidonClick(Viewv){53. if(mathService==null){54. labelView.setText("未綁定服務(wù)");55. return;56. }57. longa=Math.round(Math.random()*100);58. longb=Math.round(Math.random()*100);59. longresult=mathService.Add(a,b);60. Stringmsg=String.valueOf(a)+"+"+String.valueOf(b)+61. "="+String.valueOf(result);62. labelView.setText(msg);63. } 64.});65.}66.7.2本地服務(wù)7.2.3

服務(wù)綁定67.privateServiceConnectionmConnection=newServiceConnection(){68. @Override69. publicvoidonServiceConnected(ComponentNamename,IBinderservice){70. mathService=((MathService.LocalBinder)service).getService();71. }72.73. @Override74. publicvoidonServiceDisconnected(ComponentNamename){75. mathService=null; 76. }77.};78.}7.3

遠(yuǎn)程服務(wù)

7.3.1進(jìn)程間通信在Android系統(tǒng)中,每個(gè)應(yīng)用程序在各自的進(jìn)程中運(yùn)行,而且出于安全原因的考慮,這些進(jìn)程之間彼此是隔離的,進(jìn)程之間傳遞數(shù)據(jù)和對象,需要使用Android支持的進(jìn)程間通信(Inter-ProcessCommunication,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)接口中定義的方法和屬性在需要調(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(AndroidInterfaceDefinitionLanguage)是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.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服務(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.aidlIMathService接口僅包含一個(gè)add()方法,傳入的參數(shù)是兩個(gè)長型整數(shù),返回值也是長型整數(shù)packageedu.hrbeu.RemoteMathServiceDemo;interfaceIMathService{ longAdd(longa,longb);}7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用使用AIDL語言定義跨進(jìn)程服務(wù)的接口如果使用Eclipse編輯IMathService.aidl文件,當(dāng)用戶保存文件后,ADT會自動在/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.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的完整代碼packageedu.hrbeu.RemoteMathServiceDemo;importjava.lang.String;importandroid.os.RemoteException;importandroid.os.IBinder;importandroid.os.IInterface;importandroid.os.Binder;importandroid.os.Parcel;publicinterfaceIMathServiceextendsandroid.os.IInterface{/**Local-sideIPCimplementationstubclass.*/publicstaticabstractclassStubextendsandroid.os.Binderimplementsedu.hrbeu.RemoteMathServiceDemo.IMathService{ privatestaticfinaljava.lang.StringDESCRIPTOR="edu.hrbeu.RemoteMathServiceDemo.IMathService";/**Constructthestubatattachittotheinterface.*/ publicStub(){ this.attachInterface(this,DESCRIPTOR); }7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用16./**17.*CastanIBinderobjectintoanIMathServiceinterface,18.*generatingaproxyifneeded.19.*/20. publicstaticedu.hrbeu.RemoteMathServiceDemo.IMathServiceasInterface(android.os.IBinderobj){21. if((obj==null)){22. returnnull;23. }24. android.os.IInterfaceiin=(android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);25.if(((iin!=null)&&(iininstanceofedu.hrbeu.RemoteMathServiceDemo.IMathService))){26. return((edu.hrbeu.RemoteMathServiceDemo.IMathService)iin);27. }28. returnnewedu.hrbeu.RemoteMathServiceDemo.IMathService.Stub.Proxy(obj);29.}30.publicandroid.os.IBinderasBinder(){31. returnthis;32.}7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用33.publicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags)throwsandroid.os.RemoteException{34. switch(code) {35. caseINTERFACE_TRANSACTION:36. {37. reply.writeString(DESCRIPTOR);38. returntrue;39. }40. caseTRANSACTION_Add:41. {42. data.enforceInterface(DESCRIPTOR);43. long_arg0;44. _arg0=data.readLong();45. long_arg1;46. _arg1=data.readLong();47. long_result=this.Add(_arg0,_arg1);48. reply.writeNoException();reply.writeLong(_result);50.

returntrue;7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用51. }52. }53. returnsuper.onTransact(code,data,reply,flags);54.}55.privatestaticclassProxyimplementsedu.hrbeu.RemoteMathServiceDemo.IMathService{56. privateandroid.os.IBindermRemote;57. Proxy(android.os.IBinderremote){58. mRemote=remote;59. }60. publicandroid.os.IBinderasBinder(){61. returnmRemote;62. }63. publicjava.lang.StringgetInterfaceDescriptor(){64. returnDESCRIPTOR;65. }66. publiclongAdd(longa,longb)throwsandroid.os.RemoteException{android.os.Parcel_data=android.os.Parcel.obtain();68.android.os.Parcel_reply=android.os.Parcel.obtain();69. long_result;7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用70.

try{71. _data.writeInterfaceToken(DESCRIPTOR);72. _data.writeLong(a);73. _data.writeLong(b);74. mRemote.transact(Stub.TRANSACTION_Add,_data,_reply,0);75. _reply.readException();76. _result=_reply.readLong();77. }78. finally{79. _reply.recycle();80. _data.recycle();81. }82. return_result;83. }84.}85. staticfinalintTRANSACTION_Add=(IBinder.FIRST_CALL_TRANSACTION+0);86.}87.publiclongAdd(longa,longb)throwsandroid.os.RemoteException;88.}7.3

遠(yuǎn)程服務(wù)7.3.2服務(wù)創(chuàng)建與調(diào)用第8行代碼是IMathService繼承了android.os.IInterface,這是所有使用AIDL建立的接口都必須繼承的基類接口,這個(gè)基類接口中定義了asBinder()方法,用來獲取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行代碼是使用DESCRIPTOR構(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ù)第71~76行代碼是在該函數(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對象的形式傳遞到跨進(jìn)程服務(wù)的內(nèi)部時(shí),onTransac

溫馨提示

  • 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

提交評論