Android Service 之Bound Service


    前面提了start service 是可以独立与调用程序运行的(见),也就是说启动它的程序消亡了,该service还是可以继续运行的。

    这里的Bound Service 就没这好事了,它仅仅服务于调用它的组件,不能脱离于调用它的组件而生存。人都完蛋了,人体的一些器官有啥用呢。。。

    Bound Service 是允许其他的组件(如 Activities)绑定到其上面,可以发送请求,也可以接受请求,甚至可以进行进程间的通信。

   那么如何来创建一个Bound Service 呢?当创建一个能提供绑定功能的服务时,我们就必须要提供一个IBinder对象,客户端就可以使用IBinder对象来与服务进行交互,在Android系统中,有三种方式可以创建IBinder:

 1.扩展Binder类:这种方式当你的service只给当前的程序用而且在后台执行的时候采用这种方式比较好。意思很简单,不需要跨进程间通信。

  2.使用Message机制:消息机制相对于Binder的方式就比较复杂点,它支持跨进程间调用的(这种方式的基础其实也是AIDL,只不过不需要涉及到AIDL那么深),这种情况下,service会定义一个handle来出来不同的object的服务请求,有一点要提起的是,这里的IBinder对所有的客户端来说是共享的。当然我们的客户端也可以定义自己的handle来处理和service之间来进行交互。消息机制是一种实现进程间通信的最简单的方式,因为所有的请求都会放到一个消息队列当中去进行轮询处理(意思就是单线程啦),每次只处理一个服务请求,这样就不要保证你设计的service需要保证是线程安全状态的。

  3.使用AIDL(Android interface definition language 安卓接口定义语言)。:这种方式是最难的一种方式了,他会把所有的工作都会分解成最原始的语义,从而使得系统能够理解该工作目的。然后进行进程间的通信。前面说过message采用的是AIDL的架构基础的,当我们需要同时处理多个请求,而不是放在队列里面一个一个的处理的时候就可以采用这种方式了。使用这种方式你必须保证的你的service能够支持多线程并且保证其实线程安全状态。一般情况下会先创建一个.aldl文件来定义程序的接口,系统会为你自动自动生成抽象类以及IPC的处理,然后你就可以在你的service种进行extend了。

 本文此处介绍Binder类,后续的Message 和AIDL机制会慢慢更新上来。

如何创建一个bound service呢?
要素:
必须得实现onBind()函数,然后返回一个IBinder的接口,IBinder定义了与service通信的接口;
其它应用程序通过调用bindService()来绑定到该service上并获取接口以及调用service的方法。

service生存的唯一理由是为了绑定它的应用程序服务,因此,应用程序如果消失了,它也失去了它生存的意义了。好伟大的“爱情”,现实当中我们找不到这样的爱情,代码中找到了,HOHO。
好了,我们来梳理下创建一个bound service的过程:
首先,我们必须得定义一个客户端如何与service通信的接口,该接口必须是实现了IBinder的接口,该接口是从obBind()函数的回调方法中返回来的。一旦客户端收到了IBinder接口,就可以和service间进行通信了。

多个客户端可以和service绑定一次,当客户端与service交互结束之后,将会调用unbindService()来解除绑定,一旦整个系统中没有客户端与service进行绑定了,那么系统将会destory该service。

上个具体的例子并附注说明:

例子实现一个service来项客户端提供一个随机产生的数字功能。客户端将service提供的随机数显示在自己的界面上。

1.LocalService.java类,继承自service,代码以及注释如下:

  1. package com.android.localboundservice;  
  2.   
  3. import java.util.Random;  
  4.   
  5. import android.app.Service;  
  6. import android.content.Intent;  
  7. import android.os.Binder;  
  8. import android.os.IBinder;  
  9. import android.util.Log;  
  10.   
  11. /** 
  12.  *  
  13.  * @author bluesky 
  14.  * 创建一个bindservice 的步骤: 
  15.  * 实现一个IBinder接口类,并返回一个IBinder对象,该对象用于传递给客户端来进行调用service的服务。通常的做法是extends Binder类, 
  16.  * 应为该类实现了IBinder的接口。然后从onBind函数中返回当前service的一个实例,该实例是IBinder类型。 
  17.  * 实现service中需要提供给客户端的服务即可。 
  18.  * 至于客户端如何使用service请看客户端的操作。 
  19.  */  
  20.   
  21. public class LocalService extends Service {  
  22.   
  23.     public IBinder localBinder = new MyLocalService();  
  24.     public Random m_generator = new Random();  
  25.     public static final int num = 2000;  
  26.     private static final String TAG = "LocalService";  
  27.     /** 
  28.      *  
  29.      * @author bluesky 
  30.      * 该类作用: 
  31.      * 1.yLocalService 继承自Binder类,而Binder类是实现了IBinder接口的。该接口用于提供给客户端, 
  32.      * 可以用于客户端获取service的对象,然后调用service端的方法。 
  33.      */  
  34.     public class MyLocalService extends Binder{  
  35.         public LocalService getService(){  
  36.             Log.d(TAG, "********getService");  
  37.             return LocalService.this;  
  38.         }  
  39.     }  
  40.     /** 
  41.      * 由于是采用IBinder形式进行service绑定的,这里在绑定的时候我们要返回一个IBinder对象,该对象用于给客户端使用service的服务。 
  42.      * 该对象就是前面我们创建的MyLocalService的对象,该对象是继承了Binder类,Binder类实现了IBinder接口。 
  43.      */  
  44.     @Override  
  45.     public IBinder onBind(Intent arg0) {  
  46.         // TODO Auto-generated method stub   
  47.         Log.d(TAG, "*******return IBinder interface");  
  48.         return localBinder;  
  49.     }  
  50.       
  51.     /** 
  52.      * @param null; 
  53.      * @return 随机数。 
  54.      * service中提供的方法,用于产生一个随机数。 
  55.      */  
  56.     public int generatorInt(){  
  57.         Log.d(TAG, "******get random generator!");  
  58.         return m_generator.nextInt(num);  
  59.     }  
  60.   
  61. }  
2 LocalBoundServiceActivity.java继承自Activity作为我们的客户端:   
  1. package com.android.huawei.localboundservice;  
  2.   
  3. import com.android.localboundservice.LocalService.MyLocalService;  
  4.   
  5. import android.app.Activity;  
  6. import android.os.Bundle;  
  7. import android.os.IBinder;  
  8. import android.widget.Button;  
  9. import android.widget.Toast;  
  10. import android.util.Log;  
  11. import android.view.*;  
  12. import android.content.ComponentName;  
  13. import android.content.Context;  
  14. import android.content.Intent;  
  15. import android.content.ServiceConnection;  
  16.   
  17. /** 
  18.  *  
  19.  * @author bluesky 
  20.  * 客户端如何使用binder service 
  21.  * 1.在Activity的start的时候使用intent对象启动bindService(Intent intent,ServiceConnection conn,int flags)来进行绑定。 
  22.  * bindService的需要传递三个参数: 
  23.  * 1 绑定service的intent; 
  24.  * 2 ServiceConnection的接口变量,既然是接口,那么我们肯定需要在程序中去实现了。这个变量主要是当service连接和断开的时候传递相关的信息。需要实现两个回调函数 
  25.  * 1)onServiceConnected():当连接建立起来的时候,传递由onBind函数中返回的IBinder的接口对象。 
  26.  * 2)onServiceDisConnected():当连接异常断开的时候,系统会走到该函数处,比如说service被杀死,或者程序异常崩溃。但是必须记住:客户端调用unbindService()函数的时候 
  27.  * 是不会走到该函数处的。调用客户端消亡的时候,service跟着消亡。 
  28.  * 3:标记,这里的标记我们选择BIND_AUTO_CREATE表述当bind存在的时候自动创建service。 
  29.  *  
  30.  */  
  31. public class LocalBoundServiceActivity extends Activity {  
  32.   
  33.     private static final String TAG = "LocalBoundServiceActivity";  
  34.     private Button mBtnService = null;  
  35.     private boolean isConn = false//该标记位主要用于判断当前是连接状态呢还是断开状态   
  36.     private LocalService recSer = null;//定义一个LocalService变量,该变量继承自Binder类(实现了IBinder接口)   
  37.     /** Called when the activity is first created. */  
  38.     @Override  
  39.     public void onCreate(Bundle savedInstanceState) {  
  40.         super.onCreate(savedInstanceState);  
  41.         setContentView(R.layout.main);  
  42.         mBtnService = (Button)findViewById(R.id.bindService);  
  43.           
  44.         /** 
  45.          * 该按钮响应函数用于调用service中的随机数生成器。 
  46.          */  
  47.         mBtnService.setOnClickListener(new Button.OnClickListener(){  
  48.               
  49.             public void onClick(View v){  
  50.                 if(isConn == true){  
  51.                     int num = recSer.generatorInt();  
  52.                     Toast.makeText(LocalBoundServiceActivity.this"生成数为:"+ num, Toast.LENGTH_LONG).show();  
  53.                 }  
  54.             }  
  55.         });  
  56.     }  
  57.     @Override  
  58.     protected void onStart() {  
  59.         // TODO Auto-generated method stub   
  60.         super.onStart();  
  61.         Intent intent = new Intent(LocalBoundServiceActivity.this,LocalService.class);  
  62.         bindService(intent,mcoon,Context.BIND_AUTO_CREATE);//绑定服务   
  63.     }  
  64.     @Override  
  65.     protected void onStop() {  
  66.         // TODO Auto-generated method stub   
  67.         super.onStop();  
  68.         if(isConn){  
  69.             unbindService(mcoon);  
  70.             isConn = true;  
  71.         }  
  72.     }  
  73.     private ServiceConnection mcoon = new ServiceConnection() {  
  74.           
  75.         @Override  
  76.         public void onServiceDisconnected(ComponentName name) {  
  77.             // TODO Auto-generated method stub   
  78.             isConn = false;  
  79.             Log.d(TAG, "service disconnected!!!");  
  80.               
  81.         }  
  82.           
  83.         @Override  
  84.         public void onServiceConnected(ComponentName name, IBinder service) {  
  85.             // TODO Auto-generated method stub   
  86.               
  87.                 MyLocalService bindSer = (MyLocalService)service;  
  88.                 recSer = bindSer.getService();  
  89.                 isConn = true;  
  90.               
  91.             Log.d(TAG, "service connected!!!");  
  92.               
  93.         }  
  94.     };  
  95.       
  96. }  
最后不要忘记在你的manifest文件中加上service的注册:LocalBoundService Manifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.android.huawei.localboundservice"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <uses-sdk android:minSdkVersion="8" />  
  7.   
  8.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  9.         <activity android:name=".LocalBoundServiceActivity"  
  10.                   android:label="@string/app_name">  
  11.             <intent-filter>  
  12.                 <action android:name="android.intent.action.MAIN" />  
  13.                 <category android:name="android.intent.category.LAUNCHER" />  
  14.             </intent-filter>  
  15.         </activity>  
  16.         <service android:name=".LocalService">  
  17.         </service>  
  18.     </application>  
  19. </manifest>  
程序运行的界面如下:

OK了,结果成功显示出来了。

不知道上面的描述可否说清楚了Bounder service的用法,鄙人其实也查过不少书籍没一本书说的全的,只好自己去查官方文档和参考一些老外的书籍。中文书籍发现是真的没办法看,特别是翻译过来的,很多地方翻译的要么不通顺,要么就是曲解了作者本身的含义。还是推荐大家看英文原版的比较好。

后续会慢慢贴上message和AIDL的service机制,到时候大家一起讨论研究。

文档有不足的地方欢迎大家拍砖,讨论。

相关内容