日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[翻译]API Guides - Bound Services

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [翻译]API Guides - Bound Services 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

官方文檔原文地址:http://developer.android.com/guide/components/bound-services.html

?

一個Bound Service是一個客戶端-服務器接口的服務。一個Bound Service允許組件(像activity)綁定一個service,發送請求,接受結果,甚至進行進程間通信。一個Bound Service通常只在他向其它組件提供服務的時候運行,不會無法確定的運行在后臺的。

這篇文檔將展示你如何去創建一個Bound service,包括如何綁定一個bound service到其它的應用程序組件上。然而,你也應該關注Service的文檔來獲取更多關于常規service的額外的內容,比如如何通過service發送一條通知啦,讓service在前臺運行啦等等。 基礎 一個Bound service是Service類的一個實現,它允許其它的應用程序組件去綁定它,并且與它交互。為了能提供與service的綁定,你必須實現onBind()回調方法。這個方法返回一個IBinder對象,這個對象定義了一個客戶端可以與service進行交互的接口。 一個客戶端可以通過調用bindService()來與service進行綁定。當這個方法調用的時候,它必須提供一個ServiceConnection的實現,這個對象監控著service的連接。bindService()馬上就調用完成,并且沒有任何返回值,但是當Android系統創建客戶端與服務之間的連接時,它會調用ServiceConnection的onServiceConnected()方法,去傳遞一個用于客戶端與service交互的IBinder對象。 多個客戶端可以同時連接service。系統只在第一個客戶端綁定的時候會調用你的service的onBind()方法去獲取一個IBinder對象。然后系統會傳遞同一個IBinder給其它的客戶端,不會再調用onBind()了。 當最后一個客戶端解綁了service,系統就會摧毀這個service(除非service也通過startService()啟動)。 當你要實現自己的Bound Service,最重要的部分是你要定義onBind()返回的接口。這里有幾種不同的方式去定義service的IBinder接口,下面的部分將慢慢討論技術細節。 創建一個Bound Service 當創建一個綁定的service的時候,你必須提供一個IBinder用于客戶端與service進行交互。這里有三種定義這個接口的方式: Extending the Binder class 如果你的service對你的應用來說是私有的,并且與客戶端運行在相同的進程里,你應該通過擴展Binder類來實現你的接口,然后通過onBind()返回一個實例即可。客戶端接收Binder,并且可以直接使用它的公有方法,這些方法可能是在Binder里面,甚至可以是service里面的。 當你的service僅僅是在后臺完成一些工作的時候,這種方式是最優先的選擇。你不應該使用這種方式的唯一原因就是你的service同時需要被其他的應用程序使用。 Using a Messenger 如果你需要你的接口跨進程工作,你可以通過Messenger來為你的service創建接口。在這種方式里,Service需要定義一個Handler來響應不同類型的Message對象。這個Handler是Meesager能把IBinder對象分享給客戶端,允許客戶端通過使用Message來發送指明的基礎。另外,客戶端可以定義自己的Messenger,所以service能夠發送返回消息。 這是最簡單的進程間通信的方式,因為Messenger對壘總是一個單線程的,所以你不得不去更好的設計service讓它線程安全。 Using AIDL AIDL(Android Interface Definition Language)執行了把對象分解成能讓操作系統理解的原子功能的所有工作,這樣操作系統便可以安排它們完成進程間通信。前一個技術方案,使用Messenger,實際上是基于AIDL的。如上面所提到的,Messenger在單線程里創建一個處理所有客戶端發送的請求的隊列,所以service一次只能接受一個請求。如果你想同時處理多個請求,你可以直接使用AIDL。這種情況下,你的service必須是多線程的,并且線程安全。 想直接使用AIDL,你必須創建一個.aidl文件用來定義程序的接口。Android SDK工具使用這個文件,把它生成為一個實現了接口并且處理進程間通信的抽象類,然后你可以在你的service中擴展它。 筆記:大多數應用不應該使用AIDL來創建Bound Service的,因為它可能要求多線程的處理能力,這直接的結果就是導致非常復雜的實現。所以,AIDL不適合大多數應用,這篇文檔不會討論如何在你的service里使用它。如果你想要使用它的話,請參考AIDL的文檔。 Extending the Binder class 如果你的service只是在本地應用上使用,不需要跨進程工作,你可以實現你自己的Binder類來為客戶端提供直接訪問service里面公有方法的接口。 筆記:這樣的工作只在客戶端與service是在同一個應用,同一個進程里,這也是最常見的情況。比如說,這種方式對于一個音樂應用來說將會很好用,它需要綁定一個service到它activity的上用來在后臺播放音樂。 接下來是如何完成它: 1.在你的service里創建一個Binder的實例: 包含允許客戶端調用的公有方法。 返回當前service的實例,它有允許客戶端調用的公有方法。 或者返回service所持有的其它類的實例,里面有允許客戶端調用的公有方法。 2.在onBind()方法里返回Binder的實例。 3.在客戶端里,從onServiceConnected()方法里接收Binder對象,然后調用Bound Service所提供的方法。 筆記:service與客戶端必須在同一個應用里的原因就是客戶端可以強制轉型返回過來的對象與屬性,這樣就可以調用它的API了。service與客戶端必須在同一個進程里,這是因為技術上不允許執行任何跨進程的通信。 接下的例子,service提供了讓客戶端直接使用的方法。 publicclassLocalServiceextendsService{// Binder given to clientsprivatefinalIBinder mBinder =newLocalBinder();// Random number generatorprivatefinalRandom mGenerator =newRandom();/*** Class used for the client Binder. Because we know this service always* runs in the same process as its clients, we don't need to deal with IPC.*/publicclassLocalBinderextendsBinder{LocalService getService(){// Return this instance of LocalService so clients can call public methodsreturnLocalService.this;}}@OverridepublicIBinder onBind(Intent intent){return mBinder;}/** method for clients */publicint getRandomNumber(){return mGenerator.nextInt(100);} }

?

LocalBinder給客戶端提供了getService()方法,用來獲取當前LocalService的實例。這就允許了客戶端直接調用service里的公有方法。上面的例子里,客戶端可以調用service里面的getRandomNumber()方法。 接下來是一個綁定了LocalService的Activity,當按鈕按下的時候,調用getRandomNumber()。 publicclassBindingActivityextendsActivity{LocalService mService;boolean mBound =false;@Overrideprotectedvoid onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotectedvoid onStart(){super.onStart();// Bind to LocalServiceIntent intent =newIntent(this,LocalService.class);bindService(intent, mConnection,Context.BIND_AUTO_CREATE);}@Overrideprotectedvoid onStop(){super.onStop();// Unbind from the serviceif(mBound){unbindService(mConnection);mBound =false;}}/** Called when a button is clicked (the button in the layout file attaches to* this method with the android:onClick attribute) */publicvoid onButtonClick(View v){if(mBound){// Call a method from the LocalService.// However, if this call were something that might hang, then this request should// occur in a separate thread to avoid slowing down the activity performance.int num = mService.getRandomNumber();Toast.makeText(this,"number: "+ num,Toast.LENGTH_SHORT).show();}}/** Defines callbacks for service binding, passed to bindService() */privateServiceConnection mConnection =newServiceConnection(){@Overridepublicvoid onServiceConnected(ComponentName className,IBinder service){// We've bound to LocalService, cast the IBinder and get LocalService instanceLocalBinder binder =(LocalBinder) service;mService = binder.getService();mBound =true;}@Overridepublicvoid onServiceDisconnected(ComponentName arg0){mBound =false;}}; }

?

上面的例子展示了客戶端如何綁定service,使用ServiceConnection的實現和onServiceConnected()回調方法。接下來的部分,提供了更多的關于綁定service的信息。 筆記:上面的例子并沒有明確的從service那里解綁,但是所有的客戶端都應該在合適的時候解綁(比如當Activity pause的時候)。 想要查看更多的代碼,在ApiDemos里查看LocalService.java類與LocalServiceActivity.java類。 Using Messenger 如果你需要你的service與其他的進程進行通信,你可以使用Messenger來為你的service提供接口。這項技術允許你不使用AIDL來完成進程間通信。 下面是使用Messenger的幾個步驟:
  • service實現一個Handler為從客戶端的每一個調用接收回調。
  • Hander用來創建Messenger對象。
  • Messenger創建IBinder對象,用于客戶端從service的onBind()方法了獲取IBinder。
  • 客戶端使用IBinder來初始化Messenger,這樣客戶端可以使用它給service發送Message對象。
  • service從它的handle里接收每一個Message,準確的說,是在handleMessage()方法里。
在這種方式里,沒有任何在service里的方法給客戶端調用。取而代之的是,客戶端發送消息給service的handler獲取。 接下來是一個使用Messenger的簡單例子: publicclassMessengerServiceextendsService{/** Command to the service to display a message */staticfinalint MSG_SAY_HELLO =1;/*** Handler of incoming messages from clients.*/classIncomingHandlerextendsHandler{@Overridepublicvoid handleMessage(Message msg){switch(msg.what){case MSG_SAY_HELLO:Toast.makeText(getApplicationContext(),"hello!",Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);}}}/*** Target we publish for clients to send messages to IncomingHandler.*/finalMessenger mMessenger =newMessenger(newIncomingHandler());/*** When binding to the service, we return an interface to our messenger* for sending messages to the service.*/@OverridepublicIBinder onBind(Intent intent){Toast.makeText(getApplicationContext(),"binding",Toast.LENGTH_SHORT).show();return mMessenger.getBinder();} }

?

注意Handler里面的handleMessage()方法,servie用它來獲取消息對象,并且基于what成員屬性來決定做什么。 客戶端所要做的就是基于IBinder對象創建一個Messenger,使用這個對象通過send()方法來發送消息。下面是個簡單的例子,綁定了service的activity發送MSG_SAY_HELLO消息給service: publicclassActivityMessengerextendsActivity{/** Messenger for communicating with the service. */Messenger mService =null;/** Flag indicating whether we have called bind on the service. */boolean mBound;/*** Class for interacting with the main interface of the service.*/privateServiceConnection mConnection =newServiceConnection(){publicvoid onServiceConnected(ComponentName className,IBinder service){// This is called when the connection with the service has been// established, giving us the object we can use to// interact with the service. We are communicating with the// service using a Messenger, so here we get a client-side// representation of that from the raw IBinder object.mService =newMessenger(service);mBound =true;}publicvoid onServiceDisconnected(ComponentName className){// This is called when the connection with the service has been// unexpectedly disconnected -- that is, its process crashed.mService =null;mBound =false;}};publicvoid sayHello(View v){if(!mBound)return;// Create and send a message to the service, using a supported 'what' valueMessage msg =Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0);try{mService.send(msg);}catch(RemoteException e){e.printStackTrace();}}@Overrideprotectedvoid onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotectedvoid onStart(){super.onStart();// Bind to the servicebindService(newIntent(this,MessengerService.class), mConnection,Context.BIND_AUTO_CREATE);}@Overrideprotectedvoid onStop(){super.onStop();// Unbind from the serviceif(mBound){unbindService(mConnection);mBound =false;}} }

?

注意這個例子并沒有展示service如何回應客戶端。如果你想要service去響應客戶端,那么你需要在客戶端里也創建一個Messenger。當客戶端接收onServiceConnected()回調的時候,它向service發送一個消息,它包括了客戶端的send()方法中的replyTo參數的Messenger。 你能在MessengerService.java和MessengerServiceActivities.java中看到如何創建一個雙向的消息機制。 綁定Service 應用程序組件(客戶端)可以通過調用bindService()方法來綁定一個service。Android系統會調用service的onBind()方法,這個方法會返回一個IBinder對象用于和客戶端進行交互。 綁定的過程是異步的。bindService()很快就運行結束,并且不會返回一個IBinder對象給客戶端。為了接受IBinder,客戶端必須創建一個ServiceConnection的實例,然后把它傳給bindService()。ServiceConnection包含了供系統調用的傳遞IBinder的回調方法。 筆記:只有activities,services和content providers可以綁定service,你不可以給一個broadcast receiver綁定一個service。 所以,想要給你的客戶端綁定service,你必須: 1.實現ServiceConnection 你的實現必須覆寫兩個回調方法: onServiceConnected() 系統調用這個方法來傳遞由service的onBind()方法返回的IBinder對象。 onServiceDisconnected() Android系統調用這個方法,是當service被意外的終止了,比如service卡死了,或者被系統殺掉了。當客戶端解綁的時候,這個方法是不會被調用的。 2.調用bindService(),并傳一個ServiceConnection對象。 3.當系統調用你的onServiceConnected()方法的時候,你可以開始通過在接口中定義的方法來使用service。 4.要斷開與service的連接,調用unbindService()。 當你的客戶端被銷毀的時候,它將會解綁service,但是,你應該在你完成于service的交互或者你的activity暫停的時候去解綁service,因為這樣當service沒有被使用的時候可以停下來(更多關于何時去綁定與解綁的討論在下面)。 下面的例子展示了客戶端連接到上面extending the Binder class所創建的service,所必須做的就是把返回的IBinder對象強制轉型成LocalService的實例: LocalService mService; privateServiceConnection mConnection =newServiceConnection(){// Called when the connection with the service is established publicvoid onServiceConnected(ComponentName className,IBinder service){// Because we have bound to an explicit// service that is running in our own process, we can// cast its IBinder to a concrete class and directly access it.LocalBinder binder =(LocalBinder) service;mService = binder.getService();mBound =true;}// Called when the connection with the service disconnects unexpectedly publicvoid onServiceDisconnected(ComponentName className){Log.e(TAG,"onServiceDisconnected");mBound =false;} };

?

客戶端可以通過給bindService()方法放一個ServiceConnection參數來綁定一個service: Intent intent =newIntent(this,LocalService.class); bindService(intent, mConnection,Context.BIND_AUTO_CREATE);
  • bindService()的第一個參數是一個指定了綁定哪一個service的Intent對象(雖然intent也可以是隱式的)。
  • 第二個參數是ServiceConnection對象。
  • 第三個參數是一個綁定可選的標示符。通常為了去創建一個不存在的service,應該使用BIND_AUTO_CREATE。其它的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,或者0。
額外的提示 關于綁定service,這里有一些重要的提示:
  • 你應該總是捕獲DeadObjectException異常,這個異常將在連接被破壞的時候拋出,也是唯一一個通過遠程方法拋出的異常。
  • 在進程之間,對象的引用被計數。(?Objects are reference counted across processes)
  • 你應該總是在你客戶端的生命周期里成對的去綁定和解綁,匹配與連接與斷開的時候。
    • 如果你僅僅是希望service與你的activity交互在可見的時候,你應該在onStart()方法中綁定,onStop()方法中解綁。
    • 如果你希望你的activity能夠在自己停止前一直能接收到反饋結果,你應該在onCreate()里綁定,在onDestroy()里解綁。注意,這意味著你的activity需要一直使用service(甚至是在后臺。)所以,如果service在另一個進程里,所以你應該提高你進程的權重,這樣系統就不太可能會殺掉它了。
筆記:你不應該在onResume()和onPause()方法里綁定和解綁service,因為這些回調發生在每一次生命周期的轉換的時候,你應該把工作的過程放在轉換較少的地方。如果你的應用程序里有多個activity要綁定同一個service,這個轉換就會發生在兩個activity之間,service將會在當前activity解綁的時候(onPause())被摧毀,然后又在下一次綁定之前(onResume())被重新創建。(關于activity是如何協調生命周期來進行activity之間的轉換的更多內容,請查看Activiies的文檔。) 管理Bound Service的生命周期 當service從所有的客戶端上解綁,系統就會銷毀它(除非它同時通過了onStartCommand()方法來啟動)。所以,你不必要去管理一個僅僅是Bound Service的生命周期。 然后,如果你選擇去實現onStartCommand()方法,你就必須明確的停止service,這時service被認為是started。在這種情況下,service會一直運行,直到service通過stopSelf()或者其他組件通過stopService()來停止它。 另外,如果你的service是started的,并且接受了綁定。那么當系統調用你的onBind()方法的時候,你可以選擇返回true,這樣你可以在下次需要綁定的時候調用onRebind()方法。onRebind()方法什么都不反悔,但是客戶端仍然可以在onServiceConnected()方法接受到IBinder對象,下面的圖就展示了這種service的生命周期的邏輯。 關于更多started service的信息,請參考Services文檔。

轉載于:https://www.cnblogs.com/kross/p/3423877.html

總結

以上是生活随笔為你收集整理的[翻译]API Guides - Bound Services的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。