第7章后臺服務_第1頁
第7章后臺服務_第2頁
第7章后臺服務_第3頁
第7章后臺服務_第4頁
第7章后臺服務_第5頁
已閱讀5頁,還剩111頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第7章后臺服務本章學習目標了解Service的原理和用途掌握進程內服務的管理方法掌握服務的隱式啟動和顯式啟動方法了解線程的啟動、掛起和停止方法了解跨線程的界面更新方法掌握跨進程服務的綁定和調用方法了解AIDL語言的用途和語法

7.1

Service簡介ServiceService是Android系統的后臺服務組件,適用于開發無界面、長時間運行的應用功能

特點沒有用戶界面比Activity的優先級高,不會輕易被Android系統終止即使Service被系統終止,在系統資源恢復后Service也將自動恢復運行狀態用于進程間通信(InterProcessCommunication,IPC),解決兩個不同Android應用程序進程之間的調用和通訊問題7.1

Service簡介Service生命周期Service生命周期包括全生命周期活動生命周期onCreate()事件回調函數:

Service的生命周期開始,完成Service的初始化工作onStart()事件回調函數:活動生命周期開始,但沒有與之對應的“停止”函數,因此可以近似認為活動生命周期也是以onDestroy()標志結束onDestroy()事件回調函數:

Service的生命周期結束,釋放Service所有占用的資源7.1

Service簡介Service使用方法啟動方式綁定方式啟動方式通過調用Context.startService()啟動Service,通過調用Context.stopService()或Service.stopSefl()停止ServiceService是由其他的組件啟動的,但停止過程可以通過其他組件或自身完成如果僅以啟動方式使用的Service,這個Service需要具備自管理的能力,且不需要通過函數調用向外部組件提供數據或功能7.1

Service簡介綁定方式通過服務鏈接(Connection)或直接獲取Service中狀態和數據信息服務鏈接能夠獲取Service的對象,因此綁定Service的組件可以調用Service中的實現的函數使用Service的組件通過Context.bindService()建立服務鏈接,通過Context.unbindService()停止服務鏈接如果在綁定過程中Service沒有啟動,Context.bindService()會自動啟動Service同一個Service可以綁定多個服務鏈接,這樣可以同時為多個不同的組件提供服務7.1

Service簡介啟動方式和綁定方式的結合這兩種使用方法并不是完全獨立的,在某些情況下可以混合使用以MP3播放器為例,在后臺的工作的Service通過Context.startService()啟動某個特定音樂播放,但在播放過程中如果用戶需要暫停音樂播放,則需要通過Context.bindService()獲取服務鏈接和Service對象,進而通過調用Service的對象中的函數,暫停音樂播放過程,并保存相關信息。在這種情況下,如果調用Context.stopService()并不能夠停止Service,需要在所有的服務鏈接關閉后,Service才能夠真正的停止7.2本地服務7.2.1服務管理服務管理主要指服務的啟動和停止首先介紹實現Service的最小代碼集第1行到第3行引入必要包第5行聲明了RandomService繼承android.app.Service類在第7行到第9行重載了onBind()函數importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;

publicclassRandomServiceextendsService{ @Override publicIBinderonBind(Intentintent){ returnnull; }}7.2本地服務7.2.1服務管理onBind()函數是在Service被綁定后調用的函數,能夠返回Service的對象,在后面的內容中會詳細介紹Service的最小代碼集并不能完成任何實際的功能,需要重載onCreate()、onStart()和onDestroy(),才使Service具有實際意義Android系統在創建Service時,會自動調用onCreate()

完成必要的初始化工作在Service沒有必要再存在時,系統會自動調用onDestroy(),釋放所有占用的資源通過Context.startService(Intent)啟動Service時,onStart()則會被系統調用,Intent會傳遞給Service一些重要的參數Service會根據實際情況選擇需要重載上面的三個函數7.2本地服務7.2.1服務管理第4行、第8行和第12行的代碼重載onCreate()、onStart()和onDestroy()三個函數時,必須要在代碼中調用父函數publicclassRandomServiceextendsService{ @Override publicvoidonCreate(){ super.onCreate(); } @Override publicvoidonStart(Intentintent,intstartId){ super.onStart(intent,startId); } @Override publicvoidonDestroy(){ super.onDestroy(); }}7.2本地服務7.2.1服務管理注冊Service在AndroidManifest.xml文件中注冊,否則,這個Service根本無法啟動AndroidManifest.xml文件中注冊Service的代碼如下使用<service>標簽聲明服務,其中的android:name表示的是Service的類名稱,一定要與用戶建立的Service類名稱一致<serviceandroid:name=".RandomService"/>7.2本地服務7.2.1服務管理啟動Service啟動方式顯示啟動隱式啟動顯示啟動:在Intent中指明Service所在的類,并調用startService(Intent)函數啟動Service,示例代碼如下在Intent中指明啟動的Service在RandomSerevice.class中finalIntentserviceIntent=newIntent(this,RandomService.class);startService(serviceIntent);7.2本地服務7.2.1服務管理啟動Service隱式啟動:在注冊Service時,聲明Intent-filter的action屬性設置Intent的action屬性,可以在不聲明Service所在類的情況下啟動服務隱式啟動的代碼如下<serviceandroid:name=".RandomService"> <intent-filter> <actionandroid:name="edu.hrbeu.RandomService"/> </intent-filter></service>finalIntentserviceIntent=newIntent();serviceIntent.setAction("edu.hrbeu.RandomService");7.2本地服務7.2.1服務管理啟動Service若Service和調用服務的組件在同一個應用程序中,可以使用顯式啟動或隱式啟動,顯式啟動更加易于使用,且代碼簡潔若服務和調用服務的組件在不同的應用程序中,則只能使用隱式啟動7.2本地服務7.2.1服務管理停止Service將啟動Service的Intent傳遞給stopService(Intent)函數即可,示例代碼如下在調用startService(Intent)函數首次啟動Service后,系統會先后調用onCreate()和onStart()再次調用startService(Intent)函數,系統則僅調用onStart(),而不再調用onCreate()在調用stopService(Intent)函數停止Service時,系統會調用onDestroy()無論調用過多少次startService(Intent),在調用stopService(Intent)函數時,系統僅調用onDestroy()一次stopService(serviceIntent);7.2本地服務7.2.1服務管理示例SimpleRandomServiceDemo以顯式啟動服務在應用程序中建立Service在工程中創建RandomService服務,該服務啟動后會產生一個隨機數,使用Toast顯示在屏幕上“啟動Service”按鈕調用startService(Intent)函數,啟動RandomService服務“停止Service”按鈕調用stopService(Intent)函數,停止RandomService服務7.2本地服務7.2.1服務管理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)調用onCreate()", Toast.LENGTH_LONG).show(); }

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

23. doublerandomDouble=Math.random();24. Stringmsg="隨機數:"+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)調用onDestroy()",32. Toast.LENGTH_SHORT).show();33. }7.2本地服務7.2.1服務管理在onStart()函數中添加生產隨機數的代碼,第23行生產一個介于0和1之間的隨機數第24行代碼構造供Toast顯示的消息34. 35. @Override36. publicIBinderonBind(Intentintent){37. returnnull;38. }39.}7.2本地服務7.2.1服務管理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本地服務7.2.1服務管理在調用AndroidManifest.xml文件中,在<application>標簽下,包含一個<activity>標簽和一個<service>標簽,在<service>標簽中,聲明了RandomService所在的類14.<serviceandroid:name=".RandomService"/>15. </application>16.<uses-sdkandroid:minSdkVersion="3"/>17.</manifest>7.2本地服務7.2.1服務管理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本地服務7.2.1服務管理第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本地服務7.2.2使用線程任何耗時的處理過程都會降低用戶界面的響應速度,甚至導致用戶界面失去響應,當用戶界面失去響應超過5秒鐘,Android系統會允許用戶強行關閉應用程序較好的解決方法是將耗時的處理過程轉移到子線程上,這樣可以避免負責界面更新的主線程無法處理界面事件,從而避免用戶界面長時間失去響應7.2本地服務7.2.2使用線程線程是獨立的程序單元,多個線程可以并行工作在多處理器系統中,每個中央處理器(CPU)單獨運行一個線程,因此線程是并行工作的在單處理器系統中,處理器會給每個線程一小段時間,在這個時間內線程是被執行的,然后處理器執行下一個線程,這樣就產生了線程并行運行的假象無論線程是否真的并行工作,在宏觀上可以認為子線程是獨立于主線程,且能與主線程并行工作的程序單元7.2本地服務7.2.2使用線程使用線程實現Java的Runnable接口,并重載run()方法。在run()中放置代碼的主體部分privateRunnablebackgroudWork=newRunnable(){ @Override publicvoidrun(){ //過程代碼

} };7.2本地服務7.2.2使用線程使用線程創建Thread對象,并將上面實現的Runnable對象作為參數傳遞給Thread對象Thread的構造函數中,第1個參數用來表示線程組第2個參數是需要執行的Runnable對象第3個參數是線程的名稱調用start()方法啟動線程privateThreadworkThread;workThread=newThread(null,backgroudWork,"WorkThread");workThread.start();7.2本地服務7.2.2使用線程線程在run()方法返回后,線程就自動終止了;不推薦使用調用stop()方法在外部終止線程最好的方法是通知線程自行終止,一般調用interrupt()方法通告線程準備終止,線程會釋放它正在使用的資源,在完成所有的清理工作后自行關閉interrupt()方法并不能直接終止線程,僅是改變了線程內部的一個布爾字段,run()方法能夠檢測到這個布爾字段,從而知道何時應該釋放資源和終止線程在run()方法的代碼,一般通過Terrupted()方法查詢線程是否被中斷workTerrupt();7.2本地服務7.2.2使用線程下面的代碼是以1秒為間隔循環檢測斷線程是否被中斷第4行代碼使線程休眠1000毫秒當線程在休眠過程中被中斷,則會產生InterruptedException在中斷的線程上調用sleep()方法,同樣會產生InterruptedExceptionpublicvoidrun(){ while(!Terrupted()){ //過程代碼

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

Thread.sleep(1000); } }catch(InterruptedExceptione){ e.printStackTrace(); }}7.2本地服務7.2.2使用線程使用Handler更新用戶界面Handler允許將Runnable對象發送到線程的消息隊列中,每個Handler對象綁定到一個單獨的線程和消息隊列上當用戶建立一個新的Handler對象,通過post()方法將Runnable對象從后臺線程發送到GUI線程的消息隊列中,當Runnable對象通過消息隊列后,這個Runnable對象將被運行7.2本地服務7.2.2使用線程第1行代碼建立了一個靜態的Handler對象,但這個對象是私有的,因此外部代碼并不能直接調用這個Handler對象privatestaticHandlerhandler=newHandler();

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

}};7.2本地服務7.2.2使用線程第3行UpdateGUI()是公有的界面更新函數,后臺線程通過調用該函數,將后臺產生的數據refreshDouble傳遞到UpdateGUI()函數內部,然后并直接調用post()方法,將第6行的創建的Runnable對象傳遞給界面線程(主線程)的消息隊列中第7行到第10行代碼是Runnable對象中需要重載的run()函數,一般將界面更新代碼放置在run()函數中7.2本地服務7.2.2使用線程示例ThreadRandomServiceDemo使用線程持續產生隨機數點擊“啟動Service”后,將啟動后臺線程點擊“停止Service”后,將關閉后臺線程后臺線程每1秒鐘產生一個0到1之間的隨機數,并通過Handler將產生的隨機數顯示在用戶界面上7.2本地服務7.2.2使用線程在ThreadRandomServiceDemo示例中,RandomService.java文件是描述Service的文件,用來創建線程、產生隨機數和調用界面更新函數RandomService.java文件的完整代碼如下packageedu.hrbeu.ThreadRandomServiceDemo;

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

publicclassRandomServiceextendsService{

privateThreadworkThread;

7.2本地服務7.2.2使用線程12.

@Override13. publicvoidonCreate(){14. super.onCreate();15. Toast.makeText(this,"(1)調用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)調用onStart()",24. Toast.LENGTH_SHORT).show();25. if(!workThread.isAlive()){26. workThread.start();27. }28. }29. 7.2本地服務7.2.2使用線程30.

@Override31. publicvoidonDestroy(){32. super.onDestroy();33. Toast.makeText(this,"(3)調用onDestroy()",34. Toast.LENGTH_SHORT).show();35. workTerrupt();36. }37. 38. @Override39. publicIBinderonBind(Intentintent){40. returnnull;41. }42. 7.2本地服務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本地服務7.2.2使用線程ThreadRandomServiceDemo.java文件是界面的Activity文件,封裝Handler的界面更新函數就在這個文件中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本地服務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本地服務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本地服務7.2.2使用線程44.

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

服務綁定以綁定方式使用Service,能夠獲取到Service對象,不僅能夠正常啟動Service,而且能夠調用正在運行中的Service實現的公有方法和屬性為了使Service支持綁定,需要在Service類中重載onBind()方法,并在onBind()方法中返回Service對象,示例代碼如下7.2本地服務7.2.3

服務綁定當Service被綁定時,系統會調用onBind()函數,通過onBind()函數的返回值,將Service對象返回給調用者publicclassMathServiceextendsService{ privatefinalIBindermBinder=newLocalBinder();

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

@Override publicIBinderonBind(Intentintent){ returnmBinder; }}7.2本地服務7.2.3

服務綁定第11行代碼中可以看出,onBind()函數的返回值必須是符合IBinder接口,因此在代碼的第2行聲明一個接口變量mBinder,mBinder符合onBind()函數返回值的要求,因此將mBinder傳遞給調用者IBinder是用于進程內部和進程間過程調用的輕量級接口,定義了與遠程對象交互的抽象協議,使用時通過繼承Binder的方法實現第4行代碼繼承Binder,LocalBinder是繼承Binder的一個內部類第5行代碼實現了getService()函數,當調用者獲取到mBinder后,通過調用getService()即可獲取到Service的對象7.2本地服務7.2.3

服務綁定調用者通過bindService()函數綁定服務并在第1個參數中將Intent傳遞給bindService()函數,聲明需要啟動的Service第3個參數Context.BIND_AUTO_CREATE表明只要綁定存在,就自動建立Service;同時也告知Android系統,這個Service的重要程度與調用者相同,除非考慮終止調用者,否則不要關閉這個ServicefinalIntentserviceIntent=newIntent(this,MathService.class);bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE);7.2本地服務7.2.3

服務綁定bindService()函數的第2個參數是ServiceConnnection當綁定成功后,系統將調用ServiceConnnection的onServiceConnected()方法而當綁定意外斷開后,系統將調用ServiceConnnection中的onServiceDisconnected方法由上可知,以綁定方式使用Service,調用者需要聲明一個ServiceConnnection,并重載內部的onServiceConnected()方法和onServiceDisconnected方法7.2本地服務7.2.3

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

服務綁定取消綁定僅需要使用unbindService()方法,并將ServiceConnnection傳遞給unbindService()方法需注意的是,unbindService()方法成功后,系統并不會調用onServiceConnected(),因為onServiceConnected()僅在意外斷開綁定時才被調用unbindService(mConnection);7.2本地服務7.2.3

服務綁定通過bindService()函數綁定Servcie時,

onCreate()函數和onBinde()函數將先后被調用通過unbindService()函數取消綁定Servcie時,onUnbind()函數將被調用,如果onUnbind()函數的返回true,則表示在調用者綁定新服務時,onRebind()函數將被調用綁定方式的函數調用順序7.2本地服務7.2.3

服務綁定示例SimpleMathServiceDemo使用綁定方式使用Service創建了MathService服務,用來完成簡單的數學運算但足以說明如何使用綁定方式調用Service實例中的公有方法7.2本地服務7.2.3

服務綁定在服務綁定后,用戶可以點擊“加法運算”,將兩個隨機產生的數值傳遞給MathService服務,并從MathService對象中獲取到加法運算的結果,然后顯示在屏幕的上方“取消綁定”按鈕可以解除與MathService的綁定關系,取消綁定后,無法通過“加法運算”按鈕獲取加法運算結果7.2本地服務7.2.3

服務綁定在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本地服務7.2.3

服務綁定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本地服務7.2.3

服務綁定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本地服務7.2.3

服務綁定SimpleMathServiceDemo.java文件是界面的Activity文件,綁定和取消綁定服務的代碼在這個文件中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本地服務7.2.3

服務綁定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本地服務7.2.3

服務綁定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本地服務7.2.3

服務綁定49.50.computButton.setOnClickListener(newView.OnClickListener(){51. @Override52. publicvoidonClick(Viewv){53. if(mathService==null){54. labelView.setText("未綁定服務");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本地服務7.2.3

服務綁定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

遠程服務

7.3.1進程間通信在Android系統中,每個應用程序在各自的進程中運行,而且出于安全原因的考慮,這些進程之間彼此是隔離的,進程之間傳遞數據和對象,需要使用Android支持的進程間通信(Inter-ProcessCommunication,IPC)機制進程間通信采用Intent和跨進程服務的方式實現IPC,使應用程序具有更好的獨立性和魯棒性IPC機制包含Intent:承載數據,是一種簡單、高效、且易于使用的IPC機制遠程服務:服務和調用者在不同的兩個進程中,調用過程需要跨越進程才能實現7.3

遠程服務7.3.1進程間通信實現遠程服務的步驟使用AIDL語言定義跨進程服務的接口根據AIDL語言定義的接口,在具體的Service類中實現接口中定義的方法和屬性在需要調用跨進程服務的組件中,通過相同的AIDL接口文件,調用跨進程服務7.3

遠程服務7.3.2服務創建與調用AIDL(AndroidInterfaceDefinitionLanguage)是Android系統自定義的接口描述語言,可以簡化進程間數據格式轉換和數據交換的代碼,通過定義Service內部的公共方法,允許調用者和Service在不同進程間相互傳遞數據AIDL的IPC機制與COM和Corba非常相似,都是基于接口的輕量級進程通信機制AIDL語言的語法與Java語言的接口定義非常相似,唯一不同之處是:AIDL允許定義函數參數的傳遞方向7.3

遠程服務7.3.2服務創建與調用AIDL支持三種方向:in、out和inout標識為in的參數將從調用者傳遞到跨進程服務中標識為out的參數將從跨進程服務傳遞到調用者中標識為inout的參數將先從調用者傳遞到跨進程服務中,再從跨進程服務返回給調用者在不標識參數的傳遞方向時,缺省認定所有函數的傳遞方向為in出于性能方面的考慮,不要在參數中標識不需要的傳遞方向7.3

遠程服務7.3.2服務創建與調用遠程訪問的創建和調用需要使用AIDL語言,一般分為以下幾個過程使用AIDL語言定義跨進程服務的接口通過繼承Service類實現跨進程服務綁定和使用跨進程服務7.3

遠程服務7.3.2服務創建與調用下面以RemoteMathServiceDemo示例為參考,說明如何創建跨進程服務在這個示例中,僅定義了MathService服務,可以為遠程調用者提供加法服務使用AIDL語言定義跨進程服務的接口首先使用AIDL語言定義的MathService的服務接口,文件名為IMathService.aidlIMathService接口僅包含一個add()方法,傳入的參數是兩個長型整數,返回值也是長型整數packageedu.hrbeu.RemoteMathServiceDemo;interfaceIMathService{ longAdd(longa,longb);}7.3

遠程服務7.3.2服務創建與調用使用AIDL語言定義跨進程服務的接口如果使用Eclipse編輯IMathService.aidl文件,當用戶保存文件后,ADT會自動在/gen目錄下生成IMathService.java文件右圖是IMathService.java文件結構7.3

遠程服務7.3.2服務創建與調用使用AIDL語言定義跨進程服務的接口IMathService.java文件根據IMathService.aidl的定義,生成了一個內部靜態抽象類Stub,Stub繼承了Binder類,并實現ImathService接口在Stub類中,還包含一個重要的靜態類Proxy。如果認為Stub類實現進程內服務調用,那么Proxy類則是用來實現跨進程服務調用的,將Proxy作為Stub的內部類完全是出于使用方便的目的7.3

遠程服務7.3.2服務創建與調用使用AIDL語言定義跨進程服務的接口Stub類和Proxy類關系圖7.3

遠程服務7.3.2服務創建與調用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

遠程服務7.3.2服務創建與調用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

遠程服務7.3.2服務創建與調用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

遠程服務7.3.2服務創建與調用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

遠程服務7.3.2服務創建與調用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

遠程服務7.3.2服務創建與調用第8行代碼是IMathService繼承了android.os.IInterface,這是所有使用AIDL建立的接口都必須繼承的基類接口,這個基類接口中定義了asBinder()方法,用來獲取Binder對象在代碼的第30行到第32行,實現了android.os.IInterface接口所定義的asBinder()方法在IMathService中,絕大多數的代碼是用來實現Stub這個抽象類的。每個遠程接口都包Stub類,因為是內部類,所有并不會產生命名的沖突asInterface(IBinder)是Stub內部的跨進程服務接口,調用者可以通過該方法獲取到跨進程服務的對象7.3

遠程服務7.3.2服務創建與調用仔細觀察asInterface(IBinder)實現方法,首先判斷IBinder對象obj是否為null(第21行),如果是則立即返回第24行代碼是使用DESCRIPTOR構造android.os.IInterface對象,并判斷android.os.IInterface對象是否為進程內服務如果是進程內服務,則無需進程間通信,返回android.os.IInterface對象(第26行)如果不是進程內服務,則構造并返回Proxy對象(第28行)第66行代碼是Proxy內部包含與IMathService.aidl相同簽名的函數第71~76行代碼是在該函數中以一定的順序將所有參數寫入Parcel對象,以供Stub內部的onTransact()方法能夠正確獲取到參數7.3

遠程服務7.3.2服務創建與調用當數據以Parcel對象的形式傳遞到跨進程服務的內部時,onTransac

溫馨提示

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

評論

0/150

提交評論