zoukankan      html  css  js  c++  java
  • 【Android】17.2 Activity与Local Service的绑定

    分类:C#、Android、VS2015;

    创建日期:2016-03-03

    一、简介

    如果服务是你的应用程序所私有的,即服务(Service)与客户端(Activity)都在同一个项目中(大部分应用程序的情况都是如此),这种服务称为本地服务。

    对于本地服务,应该在继承自Binder的类中创建接口,并从重写的OnBind()方法中返回一个Binder的实例。客户端接收这个Binder对象并用它来直接访问Binder甚至Service中可用的公共(public)方法。

    二、示例1运行截图

    image  image

    三、主要设计步骤

    1、添加ch1701_main.xml文件

    在layout文件夹下添加该文件,模板选择【XML】,因为布局比较简单,就不让它带设计界面了。当然也可以添加ch1701_main.axml文件让其带设计界面。

    <?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">
      <Button
          android:id="@+id/ch1701_bind"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="启动服务绑定">
        <requestFocus />
      </Button>
      <Button
          android:id="@+id/ch1701_call"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="调用服务提供的方法">
        <requestFocus />
      </Button>
      <Button
          android:id="@+id/ch1701_unbind"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="解除服务绑定" />
    </LinearLayout>

    2、创建服务—ch1701Service

    要创建一个可被绑定的服务(bound service),必须在提供的服务中实现OnBind()回调方法,并在该方法中返回一个IBinder类型的对象,此对象定义了与服务进行通信的接口,该接口用于指明客户端如何与服务进行通信。

    ch1701Service.cs文件的代码如下:

    using Android.App;
    using Android.Content;
    using Android.OS;
    namespace MyDemos.SrcDemos
    {
        [Service]
        public class ch1701LocalService : Service
        {
            // 用于让客户端绑定的IBinder接口
            private readonly IBinder binder;
            // 用于获取随机数
            private readonly System.Random r = new System.Random();
    
            public ch1701LocalService()
            {
                binder = new ch1701LocalBinder(this);
            }
    
            public override IBinder OnBind(Intent intent)
            {
                return binder;
            }
    
            // 声明让客户端调用的公共方法
            public int GetRandomNumber()
            {
                return r.Next(100);
            }
        }
    
        // 因为本服务总是运行于与客户端相同的进程中,因此不需要用IPC进行处理。
        public class ch1701LocalBinder : Binder
        {
            // 客户端可通过它调用服务提供的公共方法
            public ch1701LocalService localService { get; private set; }
    
            public ch1701LocalBinder(ch1701LocalService service)
            {
                localService = service;
            }
        }
    }

    (1)代码解释

    (a)在MyService中包含可供客户端调用的公共方法。

    既然是服务,就要在Service中包含可供客户端调用的公共方法,该例子仅仅用GetRandomNumber()方法来演示。当然,也可以通过这些公共方法方返回其它类的实例。

    (b)从回调方法OnBind()中返回Binder的实例。

    在客户端中,通过在回调方法OnServiceConnected()中接收Binder并调用服务提供的方法,即可实现对绑定的服务进行调用。

    ch1701LocalBinder为客户端提供了localService属性,通过该属性得到ch1701LocalService的实例后,客户端就可以通过它调用服务中提供的公共方法(比如调用服务示例代码中的GetRandomNumber()方法)。

    (c)注意事项。

    服务和客户端之所以必须位于同一个应用程序中(同一个项目中),是为了让客户端能够正确转换(cast)返回的对象并调用对象的API。 另外,服务和客户端也必须位于同一个进程中,因为这种方式不能执行任何跨进程的序列化(marshalling)操作。要实现跨进程的序列化操作,可利用消息传递来实现。

    (2)创建继承自Binder的类

    要实现可被绑定的服务,除了创建服务外,还需要自定义一个继承自Binder的子类,在该子类中提供一个返回服务实例的方法。该子类是IBinder接口的默认实现。

    Binder子类通过返回的Service实例响应客户端请求。

    例如,在ch1701Service.cs文件中定义了一个名为ch1701ServiceBind的类,当客户端第1次连接服务时,Android会自动调用服务中提供的OnBind方法。这样以来,客户端就可以通过Service调用服务提供的公共方法了。

    3、创建客户端—ch1701BindingActivity.cs

    ch1701BindingActivity.cs文件的代码如下:

    using Android.App;
    using Android.Content;
    using Android.OS;
    using Android.Widget;
    namespace MyDemos.SrcDemos
    {
        [Activity(Label = "【例17-1】绑定到本地服务")]
        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)
                    {
                        // 绑定到LocalService
                        Intent 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, "请先绑定", ToastLength.Short).Show();
                        return;
                    }
                    // 注意如果该调用会导致某些操作的挂起,应该在单独的线程中调用它,
                    // 以免降低activity的性能。
                    int num = mService.GetRandomNumber();
                    Toast.MakeText(this, "获取的值为: " + num, ToastLength.Short).Show();
                };
    
                var btnUnbind = FindViewById<Button>(Resource.Id.ch1701_unbind);
                btnUnbind.Click += delegate
                {
                    // 与服务解除绑定
                    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() 回调方法绑定到服务。

    (2)将客户端绑定到服务

    客户端可以通过调用BindService() 方法来绑定服务。当客户端完成交互时,可调用UnbindService()来解除绑定。

    调用BindService() 方法来绑定服务时,必须提供一个 ServiceConnection 的实现代码,用于监控与服务的连接。

    BindService() 将会立即返回,没有返回值。但是Android系统在创建客户端与服务之间的连接时,会自动调用 ServiceConnection 中的 OnServiceConnected() 方法传递一个 IBinder ,客户端利用它即可与服务进行通信。

    ch1701ServiceConnection类负责提供客户端和服务之间的调用接口,注意该类实现了IServiceConnection接口,由于ServiceConnection类是通过Java定义的,所以ch1701ServiceConnection类必须继承自Java.Lang.Object。

    BindService方法实现的功能是:如果存在绑定,就使用Bind.AutoCreate值自动创建服务(Android 5.0及更高版本才有此选项)。该方法是一个异步调用,如果没有可绑定的服务该方法将返回false,如果有可绑定的服务,则通过回调将建立的连接发送到ch1701ServiceConnection类中的OnServiceConnected()方法。

    MyServiceConnection类继承自ServiceConnection类,在这个类中,重写了OnServiceConnected方法。在这种情况下,IBinder是MyServiceBinder的一个实例。MyServiceBinder用于获取对MyService的引用,以便客户端可以利用它调用服务中定义的方法。

    注意在MyServiceConnection的构造函数中,将MainActivity的实例传递到本类中声明的activity(例子中只是以MainActivity为例,但也可以是其他的Activity),这是为了可以在Activity中通过它自身定义的OnServiceConnected回调方法得到对服务的引用,这样以来,Activity就可以调用服务中提供的方法了。

    (3)调用服务提供的方法

    客户端通过Binder实例获取被绑定的服务的引用后,就可以调用服务中提供的方法了。在这个例子中,ch1701Service服务只定义了一个GetRandomNumber()方法。一旦Activity通过OnServiceConnected方法实现了绑定,这个Activity就可以利用binder来获取对服务的引用,随后就可以调用服务中提供的GetRandomNumber()方法了。

    (4)取消服务绑定(Unbinding from the Service)

    客户端(Activity)完成对服务的调用后,必须取消对该服务的绑定(即:在不使用服务时要及时关闭服务)。服务断开连接后,会自动调用ServiceConnection类的OnServiceDisconnected方法。

    要解除被绑定的服务,客户端调用UnbindService方法即可,通过它可传递在绑定中使用的ServiceConnection实例。

    如果没有Activity通过StartService方法调用该服务,也没有其他客户端绑定到该服务,则安卓系统将自动关闭该服务。

  • 相关阅读:
    使用MySQL存储过程连续插入多条记录
    为什么编程语言以及数据库要从1970年1月1日开始计算时
    关于shtml页面include问题解决方案
    简单实用的FTP操作类
    js实现完美身份证号有效性验证
    .htaccess文件的建立和rewrite_module的启用
    php冒泡排序
    php实现汉诺塔问题(递归)
    简单的mysql数据库备份程序
    选择排序的php实现
  • 原文地址:https://www.cnblogs.com/rainmj/p/5237276.html
Copyright © 2011-2022 走看看