【Android】17.2 Activity与Local Service的绑定
分類:C#、Android、VS2015;
創(chuàng)建日期:2016-03-03
一、簡(jiǎn)介
如果服務(wù)是你的應(yīng)用程序所私有的,即服務(wù)(Service)與客戶端(Activity)都在同一個(gè)項(xiàng)目中(大部分應(yīng)用程序的情況都是如此),這種服務(wù)稱為本地服務(wù)。
對(duì)于本地服務(wù),應(yīng)該在繼承自Binder的類中創(chuàng)建接口,并從重寫的OnBind()方法中返回一個(gè)Binder的實(shí)例。客戶端接收這個(gè)Binder對(duì)象并用它來(lái)直接訪問(wèn)Binder甚至Service中可用的公共(public)方法。
二、示例1運(yùn)行截圖
?
三、主要設(shè)計(jì)步驟
1、添加ch1701_main.xml文件
在layout文件夾下添加該文件,模板選擇【XML】,因?yàn)椴季直容^簡(jiǎn)單,就不讓它帶設(shè)計(jì)界面了。當(dāng)然也可以添加ch1701_main.axml文件讓其帶設(shè)計(jì)界面。
<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:padding="4dip"android:gravity="center_horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/ch1701_bind"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="啟動(dòng)服務(wù)綁定"><requestFocus /></Button><Buttonandroid:id="@+id/ch1701_call"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="調(diào)用服務(wù)提供的方法"><requestFocus /></Button><Buttonandroid:id="@+id/ch1701_unbind"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="解除服務(wù)綁定" /> </LinearLayout>2、創(chuàng)建服務(wù)—ch1701Service
要?jiǎng)?chuàng)建一個(gè)可被綁定的服務(wù)(bound service),必須在提供的服務(wù)中實(shí)現(xiàn)OnBind()回調(diào)方法,并在該方法中返回一個(gè)IBinder類型的對(duì)象,此對(duì)象定義了與服務(wù)進(jìn)行通信的接口,該接口用于指明客戶端如何與服務(wù)進(jìn)行通信。
ch1701Service.cs文件的代碼如下:
using Android.App; using Android.Content; using Android.OS; namespace MyDemos.SrcDemos {[Service]public class ch1701LocalService : Service{// 用于讓客戶端綁定的IBinder接口private readonly IBinder binder;// 用于獲取隨機(jī)數(shù)private readonly System.Random r = new System.Random();public ch1701LocalService(){binder = new ch1701LocalBinder(this);}public override IBinder OnBind(Intent intent){return binder;}// 聲明讓客戶端調(diào)用的公共方法public int GetRandomNumber(){return r.Next(100);}}// 因?yàn)楸痉?wù)總是運(yùn)行于與客戶端相同的進(jìn)程中,因此不需要用IPC進(jìn)行處理。public class ch1701LocalBinder : Binder{// 客戶端可通過(guò)它調(diào)用服務(wù)提供的公共方法public ch1701LocalService localService { get; private set; }public ch1701LocalBinder(ch1701LocalService service){localService = service;}} }(1)代碼解釋
(a)在MyService中包含可供客戶端調(diào)用的公共方法。
既然是服務(wù),就要在Service中包含可供客戶端調(diào)用的公共方法,該例子僅僅用GetRandomNumber()方法來(lái)演示。當(dāng)然,也可以通過(guò)這些公共方法方返回其它類的實(shí)例。
(b)從回調(diào)方法OnBind()中返回Binder的實(shí)例。
在客戶端中,通過(guò)在回調(diào)方法OnServiceConnected()中接收Binder并調(diào)用服務(wù)提供的方法,即可實(shí)現(xiàn)對(duì)綁定的服務(wù)進(jìn)行調(diào)用。
ch1701LocalBinder為客戶端提供了localService屬性,通過(guò)該屬性得到ch1701LocalService的實(shí)例后,客戶端就可以通過(guò)它調(diào)用服務(wù)中提供的公共方法(比如調(diào)用服務(wù)示例代碼中的GetRandomNumber()方法)。
(c)注意事項(xiàng)。
服務(wù)和客戶端之所以必須位于同一個(gè)應(yīng)用程序中(同一個(gè)項(xiàng)目中),是為了讓客戶端能夠正確轉(zhuǎn)換(cast)返回的對(duì)象并調(diào)用對(duì)象的API。 另外,服務(wù)和客戶端也必須位于同一個(gè)進(jìn)程中,因?yàn)檫@種方式不能執(zhí)行任何跨進(jìn)程的序列化(marshalling)操作。要實(shí)現(xiàn)跨進(jìn)程的序列化操作,可利用消息傳遞來(lái)實(shí)現(xiàn)。
(2)創(chuàng)建繼承自Binder的類
要實(shí)現(xiàn)可被綁定的服務(wù),除了創(chuàng)建服務(wù)外,還需要自定義一個(gè)繼承自Binder的子類,在該子類中提供一個(gè)返回服務(wù)實(shí)例的方法。該子類是IBinder接口的默認(rèn)實(shí)現(xiàn)。
Binder子類通過(guò)返回的Service實(shí)例響應(yīng)客戶端請(qǐng)求。
例如,在ch1701Service.cs文件中定義了一個(gè)名為ch1701ServiceBind的類,當(dāng)客戶端第1次連接服務(wù)時(shí),Android會(huì)自動(dòng)調(diào)用服務(wù)中提供的OnBind方法。這樣以來(lái),客戶端就可以通過(guò)Service調(diào)用服務(wù)提供的公共方法了。
3、創(chuàng)建客戶端—ch1701BindingActivity.cs
ch1701BindingActivity.cs文件的代碼如下:
using Android.App; using Android.Content; using Android.OS; using Android.Widget; namespace MyDemos.SrcDemos {[Activity(Label = "【例17-1】綁定到本地服務(wù)")]public class ch1701BindingActivity : Activity{ch1701LocalService mService;ch1701ServiceConnection mConnection;bool mBound = false;protected override void OnCreate(Bundle bundle){base.OnCreate(bundle);SetContentView(Resource.Layout.ch1701_main);mConnection = new ch1701ServiceConnection(this);var btnBind = FindViewById<Button>(Resource.Id.ch1701_bind);btnBind.Click += delegate{if (mBound == false){// 綁定到LocalServiceIntent intent = new Intent(this, typeof(ch1701LocalService));BindService(intent, mConnection, Bind.AutoCreate);}Toast.MakeText(this, "已綁定", ToastLength.Short).Show();};var btnCall = FindViewById<Button>(Resource.Id.ch1701_call);btnCall.Click += delegate{if(mBound==false){Toast.MakeText(this, "請(qǐng)先綁定", ToastLength.Short).Show();return;}// 注意如果該調(diào)用會(huì)導(dǎo)致某些操作的掛起,應(yīng)該在單獨(dú)的線程中調(diào)用它,// 以免降低activity的性能。int num = mService.GetRandomNumber();Toast.MakeText(this, "獲取的值為: " + num, ToastLength.Short).Show();};var btnUnbind = FindViewById<Button>(Resource.Id.ch1701_unbind);btnUnbind.Click += delegate{// 與服務(wù)解除綁定if (mBound == true){UnbindService(mConnection);Toast.MakeText(this, "綁定已解除", ToastLength.Short).Show();}};}public class ch1701ServiceConnection : Java.Lang.Object, IServiceConnection{private ch1701BindingActivity activity;public ch1701ServiceConnection(ch1701BindingActivity activity){this.activity = activity;}public void OnServiceConnected(ComponentName name, IBinder service){ch1701LocalBinder binder = (ch1701LocalBinder)service;activity.mService = binder.localService;activity.mBound = true;}public void OnServiceDisconnected(ComponentName name){activity.mBound = false;}}} }(1)代碼解釋
該例子展示了客戶端如何利用 ServiceConnection 和 OnServiceConnected() 回調(diào)方法綁定到服務(wù)。
(2)將客戶端綁定到服務(wù)
客戶端可以通過(guò)調(diào)用BindService() 方法來(lái)綁定服務(wù)。當(dāng)客戶端完成交互時(shí),可調(diào)用UnbindService()來(lái)解除綁定。
調(diào)用BindService() 方法來(lái)綁定服務(wù)時(shí),必須提供一個(gè) ServiceConnection 的實(shí)現(xiàn)代碼,用于監(jiān)控與服務(wù)的連接。
BindService() 將會(huì)立即返回,沒(méi)有返回值。但是Android系統(tǒng)在創(chuàng)建客戶端與服務(wù)之間的連接時(shí),會(huì)自動(dòng)調(diào)用 ServiceConnection 中的 OnServiceConnected() 方法傳遞一個(gè) IBinder ,客戶端利用它即可與服務(wù)進(jìn)行通信。
ch1701ServiceConnection類負(fù)責(zé)提供客戶端和服務(wù)之間的調(diào)用接口,注意該類實(shí)現(xiàn)了IServiceConnection接口,由于ServiceConnection類是通過(guò)Java定義的,所以ch1701ServiceConnection類必須繼承自Java.Lang.Object。
BindService方法實(shí)現(xiàn)的功能是:如果存在綁定,就使用Bind.AutoCreate值自動(dòng)創(chuàng)建服務(wù)(Android 5.0及更高版本才有此選項(xiàng))。該方法是一個(gè)異步調(diào)用,如果沒(méi)有可綁定的服務(wù)該方法將返回false,如果有可綁定的服務(wù),則通過(guò)回調(diào)將建立的連接發(fā)送到ch1701ServiceConnection類中的OnServiceConnected()方法。
MyServiceConnection類繼承自ServiceConnection類,在這個(gè)類中,重寫了OnServiceConnected方法。在這種情況下,IBinder是MyServiceBinder的一個(gè)實(shí)例。MyServiceBinder用于獲取對(duì)MyService的引用,以便客戶端可以利用它調(diào)用服務(wù)中定義的方法。
注意在MyServiceConnection的構(gòu)造函數(shù)中,將MainActivity的實(shí)例傳遞到本類中聲明的activity(例子中只是以MainActivity為例,但也可以是其他的Activity),這是為了可以在Activity中通過(guò)它自身定義的OnServiceConnected回調(diào)方法得到對(duì)服務(wù)的引用,這樣以來(lái),Activity就可以調(diào)用服務(wù)中提供的方法了。
(3)調(diào)用服務(wù)提供的方法
客戶端通過(guò)Binder實(shí)例獲取被綁定的服務(wù)的引用后,就可以調(diào)用服務(wù)中提供的方法了。在這個(gè)例子中,ch1701Service服務(wù)只定義了一個(gè)GetRandomNumber()方法。一旦Activity通過(guò)OnServiceConnected方法實(shí)現(xiàn)了綁定,這個(gè)Activity就可以利用binder來(lái)獲取對(duì)服務(wù)的引用,隨后就可以調(diào)用服務(wù)中提供的GetRandomNumber()方法了。
(4)取消服務(wù)綁定(Unbinding from the Service)
客戶端(Activity)完成對(duì)服務(wù)的調(diào)用后,必須取消對(duì)該服務(wù)的綁定(即:在不使用服務(wù)時(shí)要及時(shí)關(guān)閉服務(wù))。服務(wù)斷開(kāi)連接后,會(huì)自動(dòng)調(diào)用ServiceConnection類的OnServiceDisconnected方法。
要解除被綁定的服務(wù),客戶端調(diào)用UnbindService方法即可,通過(guò)它可傳遞在綁定中使用的ServiceConnection實(shí)例。
如果沒(méi)有Activity通過(guò)StartService方法調(diào)用該服務(wù),也沒(méi)有其他客戶端綁定到該服務(wù),則安卓系統(tǒng)將自動(dòng)關(guān)閉該服務(wù)。
轉(zhuǎn)載于:https://www.cnblogs.com/rainmj/p/5237276.html
總結(jié)
以上是生活随笔為你收集整理的【Android】17.2 Activity与Local Service的绑定的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: bzoj 1901: Zju2112 D
- 下一篇: 让你完全理解base64是怎么回事