欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android基本功:跨进程调用Services(AIDL Service)

来源: 开发者 投稿于  被查看 26982 次 评论:31

Android基本功:跨进程调用Services(AIDL Service)


一、AIDL Service简介

Android系统中,各个应用都运行在自己的进程中,进程之间一般无法直接进行通信,为了实现进程通信(interprocess communication,简称IPC),Android提供了AIDL Service;

二、与本地Service不同

  • 本地Service:直接把IBinder对象本身传递给客户端的ServiceConnection的onServiceConnected方法的第二个参数;

  • 远程Service:只将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数;

    三、AIDL文件

    Android需要AIDL(Android Interface Definition Language)来定义远程接口,这种接口定义语言并不是一种真正的变成语言,只是定义两个进程之间的通信接口;

    与Java接口相似,但是存在如下几点差异:

    • AIDL定义接口的源代码必须以.aidl结尾;

    • AIDL用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其它类型全部都需要导包,即使它们在同一个包中也需要导包;

      四、使用AIDL的步骤(详细代码可见AIDLService和AIDLClient项目)

      1.创建AIDL文件

      package com.example.aidlservice; 
       
      interface ICat { 
          String getColor(); 
          double getWeight(); 
      } 
      定义好AIDL文件后,ADT工具会自动在gen/com/example/aidlservice/目录下生成一个ICat.java接口,该类内部包含一个Stub内部类,实现了IBinder,ICat两个接口,这个Stub类会作为远程Service回调类;

      2.将接口暴露给客户端

      package com.example.aidlservice; 
      import java.util.Timer; 
      import java.util.TimerTask; 
      import com.example.aidlservice.ICat.Stub; 
      import android.app.Service; 
      import android.content.Intent; 
      import android.os.IBinder; 
      import android.os.RemoteException; 
       
      public class AidlService extends Service { 
          String[] colors = new String[] { "红色", "黄色", "黑色" }; 
          double[] weights = new double[] { 2.3, 3.1, 1.58 }; 
          private String color; 
          private double weight; 
          private CatBinder catBinder; 
          Timer timer = new Timer(); 
       
          @Override 
          public void onCreate() { 
              super.onCreate(); 
              catBinder = new CatBinder(); 
              timer.schedule(new TimerTask() { 
       
                  @Override    
                  public void run() { 
                      // 随机地改变service组件内的color,weight属性的值 
                      int rand = (int) (Math.random() * 3);   
                      color = colors[rand]; 
                      weight = weights[rand]; 
                      System.out.println("---------" + rand); 
                  } 
              }, 0, 800)}; 
       
          @Override 
          public IBinder onBind(Intent arg0) { 
              /**   
              * 返回CatBinder对象,在绑定本地Service情况下, 
              * 该catBinder会直接传给客户端的ServiceConnected对象的ServiceConnected 
              * ()方法的第二个参数;在绑定远程Service的情况下  
              * ,只将catBinder对象的代理传给客户端的ServiceConnected对象的ServiceConnected()方法的第二个参数 
              */ 
              return catBinder; 
          } 
       
          @Override 
          public void onDestroy() { 
              timer.cancel(); 
          } 
       
          /**    
          * 继承Stub,也就是实现了ICat接口,并实现了IBinder接口 
          *  
          * @author pengcx 
          * 
          */ 
          public class CatBinder extends Stub { 
              @Override 
              public String getColor() throws RemoteException { 
                  return color; 
              } 
       
          @Override 
              public double getWeight() throws RemoteException { 
                  return weight; 
              } 
          } 
      } 

      在AndroidManifext.xml文件中配置该Service;

       
           
               
           
        

      3.客户端访问AIDLService

      将Service端的AIDL文件复制到客户端中,注意要在相同的包名下。

      package com.example.aidlclient; 
       
      import com.example.aidlservice.ICat; 
      import android.os.Bundle; 
      import android.os.IBinder; 
      import android.os.RemoteException; 
      import android.view.View; 
      import android.view.View.OnClickListener; 
      import android.widget.Button; 
      import android.widget.EditText; 
      import android.app.Activity; 
      import android.app.Service; 
      import android.content.ComponentName; 
      import android.content.Intent; 
      import android.content.ServiceConnection; 
       
      public class AidlClient extends Activity { 
          private ICat catService; 
          private Button getButton; 
          private EditText colorEditText, weightEditText; 
       
          private ServiceConnection conn = new ServiceConnection() { 
              @Override 
              public void onServiceDisconnected(ComponentName name) { 
                  catService = null; 
              } 
       
              @Override 
              public void onServiceConnected(ComponentName name, IBinder service) { 
                  // 获取远程Service的onBinder方法返回的对象代理 
                  catService = ICat.Stub.asInterface(service); 
              } 
          }; 
       
          @Override 
          protected void onCreate(Bundle savedInstanceState) { 
              super.onCreate(savedInstanceState); 
              setContentView(R.layout.activity_aidl_client); 
       
              getButton = (Button) findViewById(R.id.getbutton); 
              colorEditText = (EditText) findViewById(R.id.coloredittext); 
              weightEditText = (EditText) findViewById(R.id.weightedittext); 
       
              // 创建所需要绑定的Service的Intent 
              Intent intent = new Intent(); 
              intent.setAction("org.crazyit.aidl.action.AIDL_SERVICE"); 
              // 绑定远程的服务 
              bindService(intent, conn, Service.BIND_AUTO_CREATE); 
                   
              getButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
          // 获取并显示远程service的状态 
          try { 
              colorEditText.setText(catService.getColor()); 
              weightEditText.setText(catService.getWeight() + ""); 
          } catch (RemoteException e) { 
              e.printStackTrace(); 
          } 
      } 
             }); 
          } 
       
          @Override 
          protected void onDestroy() { 
              super.onDestroy(); 
              // 解除绑定 
              this.unbindService(conn); 
          } 
      } 

      错误:java.lang.SecurityException: Binder invocation to an incorrect interface。在使用上请注意,服务端与客户端都要有相同的接口(使用到的),这里的“相同”是指完全相同,包括包名,也就是说要在不同工程下建立相同的包名。

用户评论