Android每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。 
通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。 

本文以phone book service为例,即可在其他应用中根据用户ID获取用户的信息。

1 Service

首先,我们在Src目录下创建IPhoneBookService接口(IPhoneBookService.aidl),该接口为aidl文件,根据传入的ID获取用户信息.在该文件中需要导入import com.synvata.phone.User;

package com.synvata.phone;

import com.synvata.phone.User;

interface IPhoneBookService{
    User lookUpPhone(long id);
}

当我们保存文件时,Android ADT工具会自动在gen目录下生成IPhoneBookService.java文件,在文件中我们看到自动生成了Stub 类

public static abstract class Stub extends android.os.Binder implements com.synvata.phone.IPhoneBookService

该类继承于Binder,并且实现了IPhoneBookService,也就是说RemoteService类和普通的Service类没什么不同,只是返回的IBinder对象比较特别,是实现了AIDL接口的Binder。

同样,类似于本地服务,我们创建远程服务并且实现OnBind方法,PhoneBookService,并且定义一个内部类,用于向Client返回stup实例

package com.synvata.phone;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class PhoneBookService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub    
        return new PhoneServiceImpl();
    }
    
    public class PhoneServiceImpl extends IPhoneBookService.Stub{
        @Override
        public User lookUpPhone(long id) throws RemoteException {
            User usr=new User();
            usr.setId(101L);
            usr.setAge(30);
            usr.setPhone("123 456 7890");
            usr.setRegistered(true);   

            // Anonymous user
            User anonym = new User();
            anonym.setPhone("Not Published");
            anonym.setRegistered(false); 
            return ( id == usr.getId() ? usr : anonym );
        }
        
    }

}

由于我们需要向Client返回一个实例,因此采用Parcel方法使User实现Parcelable接口,同Using the Android Parcel一文中介绍,代码相同,使得User可以序列化并通过进程边界有序传输。

同时我们还要在Src中创建User.aidl,这个文件中有两行代码:

package com.synvata.phone;

parcelable User;

为什么要创建这个文件?AIDL contract方法要求,在Service中使用的每一个实现了Parcelable方法类都要创建单独的.aidl文件

最后,我们在AndroidManifest,xml中配置Service

<service 
            android:name=".PhoneBookService"  android:process=":remote">
            <intent-filter>
                <action android:name="com.synvata.phone.IPhoneBookService"></action>
            </intent-filter>
        </service>

android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。

至此,Service端创建完成。

2 Client

客户端与local service基本相同,只是需要把Service中gen下的类包导入到Src中,但是gen包下没有User类,因此还需要把Service中的User.java导入,否则无法创建User实例。前文介绍过,绑定这个Service需要三个参数bindService(intent,conn,Service.BIND_AUTO_CREATE);第一个是 Intent;第二个是ServiceConnection对象,我们创建该对象实现其onServiceConnected()和 onServiceDisconnected()来判断连接成功或断开连接,第三个参数是如何创建Service,一般指定绑定时自动创建。

IPhoneBookService phoneBookService;

    ServiceConnection connection=new ServiceConnection() {
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            phoneBookService=null;
        }
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            phoneBookService=IPhoneBookService.Stub.asInterface(service);
        }
    };

绑定之后,我们就能通过phoneBookService来访问远程Service的方法,就像使用本地方法一样

Intent intent=new Intent("com.synvata.phone.IPhoneBookService");
bindService(intent, connection, Context.BIND_AUTO_CREATE);
User usrUser=phoneBookService.lookUpPhone(101L);

android remount没有权限 android remote service_User

 

 Remote.zip