Android 跨进程通讯技术:AIDL

1.什么是AIDL

IPC(Inter Process Communication)是Android为了能让进程间进行通讯而提出来的,其中AIDL(Android Interface Definition Language,Android接口定义语言)是IPC的一个轻量级的实现,编译器通过*.aidl文件生成对应的Java代码,供我们调用。


2.例子

2.1 需要了解的:如果对于bindService还不够熟悉,先了解一下会比较好。
2.2 例子简介:2个进程,一个服务端,一个客户端,服务端初始化一些消息,客户端跨进程拿到服务端的信息,进而显示。
2.3 服务端:


IMyService.aidl

import com.cxy.aidl.Person;

interface IMyService {

 List<Person> getPersons();
 void addPerson(in Person person);
}

在这里需要注意一下,AIDL的传输规则只允许基本的数据类型,而其他自定义class都必须显式import,即使是本包下的class,且必须标识其输入输出类型,这里用in标记,表示输入型参数。如果你使用的IDE是Eclipse,且开启了自动编译,可以看到在项目的gen目录下自动生成了一个代理类:
public static abstract class Stub extends android.os.Binder implements com.cxy.aidl.IMyService   大家可以看下自己的程序是否成功生成。

Person.aidl

package com.cxy.aidl;

parcelable Person;

注意:parcelable 是小写,Person大写。

Person.java


public final class Person implements Parcelable {
 
 public String name;
 public int sex;
 public int age;
 
 public Person() {
 
 }
 
 public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {
 
  @Override
  public Person[] newArray(int size) {
   // TODO Auto-generated method stub
   return new Person[size];
  }
 
  @Override
  public Person createFromParcel(Parcel source) {
   // TODO Auto-generated method stub
   return new Person(source);
  }
 };
 
 public Person(Parcel in) {
  readFromParcel(in);
 }
 private void readFromParcel(Parcel in) {
  name = in.readString();
  sex = in.readInt();
  age = in.readInt();
 }
 
 @Override
 public int describeContents() {
  return 0;
 }
 @Override
 public void writeToParcel(Parcel dest, int flags) {
  dest.writeString(name);
  dest.writeInt(sex);
  dest.writeInt(age);
 }
 
 @Override
 public String toString() {
  return String.format(Locale.ENGLISH, "Studeng[ %s, %d, %d ]\n", name, sex, age);
 }
 
}
android sdk中提供了轻量级的序列化方法,非基本类型的对象在AIDL中传输需要被序列化,即 Parcelable  接口。


MyService.java


public class MyService extends Service {
 
 private final String TAG = MyService.class.getSimpleName();
 private static final String ACCESS_PACKAGE_NAME = "com.example.aidlclient";
 
 private boolean mCanRun = true;
 private List<Person> mPersons = new ArrayList<Person>();
 
 private final IMyService.Stub mBinder = new Stub() {
 
  // 在这里可以做权限认证,只允许包名为com.example.aidlclient的客户端通过,return false意味着客户端的调用会失败,比如下面,
  // 其他应用将无法完成调用过程
  public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException {
   String packageName = null;
   String[] packages = MyService.this.getPackageManager().getPackagesForUid(getCallingUid());
   if (packages != null && packages.length > 0) {
    packageName = packages[0];
   }
   
   Log.d(TAG, "onTransact:" + packageName);
   
   if (!ACCESS_PACKAGE_NAME.equals(packageName)) {
    return false;
   }
   
   return super.onTransact(code, data, reply, flags);
  }
  @Override
  public List<Person> getPersons() throws RemoteException {
   synchronized (mPersons) {
    return mPersons;
   }
  }
  @Override
  public void addPerson(Person person) throws RemoteException {
   synchronized (mPersons) {
    if (!mPersons.contains(person))
     mPersons.add(person);
   }
  };
 };
 
 @Override
 public void onCreate() {
  Log.d(TAG, "onCreate");
  Thread thread = new Thread(null, new ServiceRunnable(), "BackgroundService");
  thread.start();
 
  synchronized (mPersons) {
   for (int i = 1; i < 3; i++) {
    Person student = new Person();
    student.name = "student#" + i;
    student.age = i * 15;
    mPersons.add(student);
   }
  }
 
  super.onCreate();
 }
 
 @Override
 public IBinder onBind(Intent intent) {
  Log.d(TAG, String.format("onBind, intent = %s", intent.toString()));
  return mBinder;
 }
 
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  // TODO Auto-generated method stub
  return super.onStartCommand(intent, flags, startId);
 }
 
 @Override
 public void onDestroy() {
  mCanRun = false;
  super.onDestroy();
 }
 
    class ServiceRunnable implements Runnable {
        int counter = 0;
        @Override
        public void run() {
            // do background processing here.....
            while(mCanRun) {
                Log.d(TAG, "counter:"+counter);
                counter ++;
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
这里创建了服务端的Service,初始化了mPersons信息,通过mBinder输出信息,然后在onBind中返回当前binder对象。在 onTransact这里做了权限控制,具体在代码中已有注释。


AndroidManifest.xml

<service
            android:name="com.cxy.main.MyService"
            android:exported="true"
            android:process=":remote" >
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="com.cxy.main.MyService" />
            </intent-filter>
        </service>

由此已经实现了服务端的程序,但它是“死”的,单纯提供了数据,真正对数据进行处理的是客户端,接下来,new 一个新的工程:


2.4 客户端:

客户端也需要在相同的报下创建同名的aidl文件,在这里把服务端程序下的com.cxy.aidl包整个拷贝至客户端,也就是说,服务端和客户端的程序是一致的。如不一直,则程序会crash掉。下面是客户端的MainActivity.java代码,主要区别在这里。


MainActivity.java

public class MainActivity extends Activity {
 
 private final String ACTION_BIND_SERVICE = "com.cxy.main.MyService";
 private IMyService mIMyService;
 
 private ServiceConnection mServiceConnection = new ServiceConnection() {
 
  @Override
  public void onServiceDisconnected(ComponentName name) {
   mIMyService = null;
  }
 
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   // 通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用他的方法了
   mIMyService = IMyService.Stub.asInterface(service);
   try {
    Person person = mIMyService.getPersons().get(0);
    showDialog(person.toString());
   } catch (RemoteException e) {
    e.printStackTrace();
   }
  }
 };
 
 public void showDialog(String message) {
        new AlertDialog.Builder(MainActivity.this)
                .setTitle("cxy")
                .setMessage(message)
                .setPositiveButton("确定", null)
                .show();
    }

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 
  Button btn = (Button) findViewById(R.id.btn);
  btn.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // 开启访问服务端Service
    Intent intentService = new Intent(ACTION_BIND_SERVICE);
             intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
   }
  });
 }
 
 @Override
    protected void onDestroy() {
        if (mIMyService != null) {
            unbindService(mServiceConnection);
        }
        super.onDestroy();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值