Binder AIDL

来源:互联网 发布:au3写erp源码 编辑:程序博客网 时间:2024/06/02 04:27

Activity和Service传递数据

如果你的service仅被自己的应用使用并且不需跨进程工作,那么你可以实现你自己的Binder类使得你的客户端能直接使用service的公开接口方法.


注:这只在客户端和service位于同一应用和同一进程中时才能工作,其实大多数都是这种情况.例如,在一个音乐应用需要把它的activity绑定到它自己的播放音乐的后台service时,这种方式就会很好地工作.


下面是如何建立它:

  1. 在你的service中,创建一个Binder实例,提供以下三种功能之一:

  • Binder包含一些可供客户端调用的公开方法.

  • 返回当前的Service实例,它具有一些客户端可以调用的公开方法.

  • 或者,返回另一个类的实例,这个类具有客户端可调用的公开方法并托管于service

  1. 在回调方法onBind()中返回这个Binder的实例.

  2. 在客户端,从回调方法onServiceConnected()中接收这个Binder并使用1中所述的公开方法调用绑定service


注:service和客户端必须位于同一应用的理由是这样可以使客户端正确地转换返回的对象并调用它的公开方法.service和客户端必需要位于同一个进程中,因为这样就不必执行跨进程的封送处理了.


例如,这下面这个service提供让客户端通过一个Binder实现调用service中的方法的功能:

[java] view plaincopy
  1. public class LocalService extends Service {  
  2.     // Binder given to clients  
  3.     private final IBinder mBinder = new LocalBinder();  
  4.     // Random number generator  
  5.     private final Random mGenerator = new Random();  
  6.   
  7.     /** 
  8.      * 用于客户端Binder的类.因为我们我们知道这个 
  9.      * service永远运行在与客户端相同的进程中,所以我们不需要处理IPC. 
  10.      */  
  11.     public class LocalBinder extends Binder {  
  12.         LocalService getService() {  
  13.             // 返回本service的实例到客户端,于是客户端可以调用本service的公开方法  
  14.             return LocalService.this;  
  15.         }  
  16.     }  
  17.   
  18.     @Override  
  19.     public IBinder onBind(Intent intent) {  
  20.         return mBinder;  
  21.     }  
  22.   
  23.     /**客户端所要调用的方法*/  
  24.     public int getRandomNumber() {  
  25.       return mGenerator.nextInt(100);  
  26.     }  
  27. }  

LocalBinder提供提供了getService()方法使得客户端能取得当前LocalService的实例.于是客户端就可以调用service中的公开方法了.比如,客户端可以调用servicegetRandomNumber()方法.


下面是一个绑定到LocalService并且在按钮按下时调用getRandomNumber()actvity的例子:

[java] view plaincopy
  1. public class BindingActivity extends Activity {  
  2.     LocalService mService;  
  3.     boolean mBound = false;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.     }  
  10.   
  11.     @Override  
  12.     protected void onStart() {  
  13.         super.onStart();  
  14.         // 绑定到类LocalService的实例  
  15.         Intent intent = new Intent(this, LocalService.class);  
  16.         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  17.     }  
  18.   
  19.     @Override  
  20.     protected void onStop() {  
  21.         super.onStop();  
  22.         // 从service解除绑定  
  23.         if (mBound) {  
  24.             unbindService(mConnection);  
  25.             mBound = false;  
  26.         }  
  27.     }  
  28.   
  29.     /** 当按钮按下时调用(在layout文件中定义的button并用android:onClick 属性指定响应到本方法) */  
  30.     public void onButtonClick(View v) {  
  31.         if (mBound) {  
  32.             // 调用LocalService的一个方法  
  33.             // 然而,如果这个调用中有挂起操作,那么这个请求应发  
  34.             // 生在另一个线程来避免拉低activity的性能.  
  35.             int num = mService.getRandomNumber();  
  36.             Toast.makeText(this"number: " + num, Toast.LENGTH_SHORT).show();  
  37.         }  
  38.     }  
  39.   
  40.     /** 定义service绑定的回调,传给bindService() 的*/  
  41.     private ServiceConnection mConnection = new ServiceConnection() {  
  42.   
  43.         @Override  
  44.         public void onServiceConnected(ComponentName className,  
  45.                 IBinder service) {  
  46.             //我们已经绑定到了LocalService,把IBinder进行强制类型转换并且获取LocalService实例.  
  47.             LocalBinder binder = (LocalBinder) service;  
  48.             mService = binder.getService();  
  49.             mBound = true;  
  50.         }  
  51.   
  52.         @Override  
  53.         public void onServiceDisconnected(ComponentName arg0) {  
  54.             mBound = false;  
  55.         }  
  56.     };  
  57. }  

上面的例子展示了客户端如何使用一个ServiceConnection的实例和onServiceConnected()方法绑定到service

注:上面的例子没有明确地从service解除绑定.但是所有的客户端都应该在合适的时候解除绑定(比如当activity暂停时).


基础知识

  一个绑定的service是一个允许应用绑定然后进行交互的类Service的实现.要为service提供绑定,你必须实现onBind()回调方法.此方法返回一个IBinder对象,此对象定义了客户端可以用来与service交互的程序接口.


  一个客户端可以通过调用bindService()绑定到service.当它这样做时,它必须提供了一个ServiceConnection的实现.这个实现用于监视客户端与service的连接.bindService()方法会立即返回并且不会返回任何值,但当Android系统创建客户端与service之间的连接时,它调用ServiceConnectiononServiceConnected()来传送客户端用来与servcie通信的IBinder


  多个客户端可以同时连接到一个service.然而,系统只在第一个客户端绑定时才调用你的serviceonBind()方法来接收IBinder.之后系统把同一个IBinder传给其它客户端,所以不会再调用onBind()


AIDL

建立AIDL服务要比建立普通的服务复杂一些,具体步骤如下:

       (1)在Eclipse Android工程的Java包目录中建立一个扩展名为aidl的文件。该文件的语法类似于Java代码,但会稍有不同。详细介绍见实例52的内容。
       (2)如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java)。
       (3)建立一个服务类(Service的子类)。
       (4)实现由aidl文件生成的Java接口。
       (5)在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。

       建立AIDL服务

       本例中将建立一个简单的AIDL服务。这个AIDL服务只有一个getValue方法,该方法返回一个String类型的值。在安装完服务后,会在客户端调用这个getValue方法,并将返回值在TextView组件中输出。建立这个AIDL服务的步骤如下:
      (1)建立一个aidl文件。在Java包目录中建立一个IMyService.aidl文件。IMyService.aidl文件的位置如图

IMyService.aidl文件的内容如下:

Java代码:
package eoe.demo;

interface IMyService { 
String getValue(); 
}


       IMyService.aidl文件的内容与Java代码非常相似,但要注意,不能加修饰符(例如,public、private)、AIDL服务不支持的数据类型(例如,InputStream、OutputStream)等内容。

       (2)如果IMyService.aidl文件中的内容输入正确,ADT会自动生成一个IMyService.java文件。读者一般并不需要关心这个文件的具体内容,也不需要维护这个文件。关于该文件的具体内容,读者可以查看本节提供的源代码。
       (3)编写一个MyService类。MyService是Service的子类,在MyService类中定义了一个内嵌类(MyServiceImpl),该类是IMyService.Stub的子类。MyService类的代码如下:

Java代码:

package eoe.demo;import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException;public class MyService extends Service { public class MyServiceImpl extends IMyService.Stub { @Override public String getValue() throws RemoteException { return "Android/OPhone开发讲义"; } } @Override public IBinder onBind(Intent intent) { return new MyServiceImpl(); }}



       在编写上面代码时要注意如下两点:

       IMyService.Stub是根据IMyService.aidl文件自动生成的,一般并不需要管这个类的内容,只需要编写一个继承于IMyService.Stub类的子类(MyServiceImpl类)即可。

       onBind方法必须返回MyServiceImpl类的对象实例,否则客户端无法获得服务对象。

       (4)在AndroidManifest.xml文件中配置MyService类,代码如下:

Java代码:
<service android:name=".MyService" > 
<intent-filter> 
<action android:name="net.blogjava.mobile.aidl.IMyService" /> 
</intent-filter> 
</service> 


        下面来编写客户端的调用代码。首先新建一个Eclipse Android工程(ch08_aidlclient),并将自动生成的IMyService.java文件连同包目录一起复制到ch08_aidlclient工程的src目录中,如图所示。


       调用AIDL服务首先要绑定服务,然后才能获得服务对象,代码如下:


Java代码:

package net.blogjava.mobile;import net.blogjava.mobile.aidl.IMyService; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;public class Main extends Activity implements OnClickListener { private IMyService myService = null; private Button btnInvokeAIDLService; private Button btnBindAIDLService; private TextView textView; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 获得服务对象 myService = IMyService.Stub.asInterface(service); btnInvokeAIDLService.setEnabled(true); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnBindAIDLService: // 绑定AIDL服务 bindService(new Intent("net.blogjava.mobile.aidl.IMyService"), serviceConnection, Context.BIND_AUTO_CREATE); break; case R.id.btnInvokeAIDLService: try { textView.setText(myService.getValue()); // 调用服务端的getValue方法 } catch (Exception e) { } break; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService); btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService); btnInvokeAIDLService.setEnabled(false); textView = (TextView) findViewById(R.id.textview); btnInvokeAIDLService.setOnClickListener(this); btnBindAIDLService.setOnClickListener(this); }} 


原创粉丝点击