android開發AIDL實例

   由於每個應用程序都運行在自己的進程空間,並且可以從應用程序UI運行另一個服務進程,而且經常會在不同的進程間傳遞對象。在Android平臺,一個進程通常不能訪問另一個進程的內存空間。但是android提供瞭AIDL可以用來進程間數據傳遞。

         AIDL (Android Interface Definition Language) 是一種IDL 語言,用於生成可以在Android設備上兩個進程之間進行進程間通信(interprocess communication, IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。
    AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。

          下面通過一個實例來演示AIDL,因為是進程之間數據傳遞,所以這裡要使用建立android工程,一個是AIDL的服務端另一個是客戶端.

          服務端的實現步驟:

        1.創建.aidl文件      IMyService.aidl

         [html] package cn.com.karl.aidl; 
import cn.com.karl.aidl.Person; 
 
interface IMyService { 
     void savePersonInfo(in Person person); 
     List<Person> getAllPerson(); 
     String sayHello(); 

package cn.com.karl.aidl;
import cn.com.karl.aidl.Person;

interface IMyService {
     void savePersonInfo(in Person person);
     List<Person> getAllPerson();
     String sayHello();
}

     
       因為這裡用到瞭Peson對象,所以要創建一個person類。Person類,是一個序列化的類,這裡使用Parcelable 接口來序列化,是Android提供的一個比Serializable 效率更高的序列化類。

        [html] public class Person implements Parcelable { 
 
    private String name; 
    private String telNumber; 
    private int age; 
 
    public Person() {} 
 
    public Person(Parcel pl){ 
            name = pl.readString(); 
            telNumber = pl.readString(); 
            age = pl.readInt(); 
    } 
 
    public String getName() { 
            return name; 
    } 
 
    public void setName(String name) { 
            this.name = name; 
    } 
 
    public String getTelNumber() { 
            return telNumber; 
    } 
 
    public void setTelNumber(String telNumber) { 
            this.telNumber = telNumber; 
    } 
 
    public int getAge() { 
            return age; 
    } 
 
    public void setAge(int age) { 
            this.age = age; 
    } 
 
    @Override 
    public int describeContents() { 
            return 0; 
    } 
 
    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
            dest.writeString(name); 
            dest.writeString(telNumber); 
            dest.writeInt(age); 
    } 
 
    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { 
 
            @Override 
            public Person createFromParcel(Parcel source) { 
                    return new Person(source); 
            } 
 
            @Override 
            public Person[] newArray(int size) { 
                    return new Person[size]; 
            } 
 
    }; 

public class Person implements Parcelable {

    private String name;
    private String telNumber;
    private int age;

    public Person() {}

    public Person(Parcel pl){
            name = pl.readString();
            telNumber = pl.readString();
            age = pl.readInt();
    }

    public String getName() {
            return name;
    }

    public void setName(String name) {
            this.name = name;
    }

    public String getTelNumber() {
            return telNumber;
    }

    public void setTelNumber(String telNumber) {
            this.telNumber = telNumber;
    }

    public int getAge() {
            return age;
    }

    public void setAge(int age) {
            this.age = age;
    }

    @Override
    public int describeContents() {
            return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeString(telNumber);
            dest.writeInt(age);
    }

    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {

            @Override
            public Person createFromParcel(Parcel source) {
                    return new Person(source);
            }

            @Override
            public Person[] newArray(int size) {
                    return new Person[size];
            }

    };
}
           然後創建Person.aidl文件,註意這裡的parcelable小寫。

          [html] package cn.com.karl.aidl; 
parcelable Person; 
package cn.com.karl.aidl;
parcelable Person;         上面的IMyService.aidl保存以後會在gen的相應目錄下啟動生成如下代碼:

Binder[html] package cn.com.karl.aidl; 
public interface IMyService extends android.os.IInterface 

/** Local-side IPC implementation stub class. */ 
public static abstract class Stub extends android.os.Binder implements cn.com.karl.aidl.IMyService 

private static final java.lang.String DESCRIPTOR = "cn.com.karl.aidl.IMyService"; 
/** Construct the stub at attach it to the interface. */ 
public Stub() 

this.attachInterface(this, DESCRIPTOR); 

/** 
 * Cast an IBinder object into an cn.com.karl.aidl.IMyService interface, 
 * generating a proxy if needed. 
 */ 
public static cn.com.karl.aidl.IMyService asInterface(android.os.IBinder obj) 

if ((obj==null)) { 
return null; 

android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR); 
if (((iin!=null)&&(iin instanceof cn.com.karl.aidl.IMyService))) { 
return ((cn.com.karl.aidl.IMyService)iin); 

return new cn.com.karl.aidl.IMyService.Stub.Proxy(obj); 

public android.os.IBinder asBinder() 

return this; 

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 

switch (code) 

case INTERFACE_TRANSACTION: 

reply.writeString(DESCRIPTOR); 
return true; 

case TRANSACTION_savePersonInfo: 

data.enforceInterface(DESCRIPTOR); 
cn.com.karl.aidl.Person _arg0; 
if ((0!=data.readInt())) { 
_arg0 = cn.com.karl.aidl.Person.CREATOR.createFromParcel(data); 

else { 
_arg0 = null; 

this.savePersonInfo(_arg0); 
reply.writeNoException(); 
return true; 

case TRANSACTION_getAllPerson: 

data.enforceInterface(DESCRIPTOR); 
java.util.List<cn.com.karl.aidl.Person> _result = this.getAllPerson(); 
reply.writeNoException(); 
reply.writeTypedList(_result); 
return true; 

case TRANSACTION_sayHello: 

data.enforceInterface(DESCRIPTOR); 
java.lang.String _result = this.sayHello(); 
reply.writeNoException(); 
reply.writeString(_result); 
return true; 


return super.onTransact(code, data, reply, flags); 

private static class Proxy implements cn.com.karl.aidl.IMyService 

private android.os.IBinder mRemote; 
Proxy(android.os.IBinder remote) 

mRemote = remote; 

public android.os.IBinder asBinder() 

return mRemote; 

public java.lang.String getInterfaceDescriptor() 

return DESCRIPTOR; 

public void savePersonInfo(cn.com.karl.aidl.Person person) throws android.os.RemoteException 

android.os.Parcel _data = android.os.Parcel.obtain(); 
android.os.Parcel _reply = android.os.Parcel.obtain(); 
try { 
_data.writeInterfaceToken(DESCRIPTOR); 
if ((person!=null)) { 
_data.writeInt(1); 
person.writeToParcel(_data, 0); 

else { 
_data.writeInt(0); 

mRemote.transact(Stub.TRANSACTION_savePersonInfo, _data, _reply, 0); 
_reply.readException(); 

finally { 
_reply.recycle(); 
_data.recycle(); 


public java.util.List<cn.com.karl.aidl.Person> getAllPerson() throws android.os.RemoteException 

android.os.Parcel _data = android.os.Parcel.obtain(); 
android.os.Parcel _reply = android.os.Parcel.obtain(); 
java.util.List<cn.com.karl.aidl.Person> _result; 
try { 
_data.writeInterfaceToken(DESCRIPTOR); 
mRemote.transact(Stub.TRANSACTION_getAllPerson, _data, _reply, 0); 
_reply.readException(); 
_result = _reply.createTypedArrayList(cn.com.karl.aidl.Person.CREATOR); 

finally { 
_reply.recycle(); 
_data.recycle(); 

return _result; 

public java.lang.String sayHello() throws android.os.RemoteException 

android.os.Parcel _data = android.os.Parcel.obtain(); 
android.os.Parcel _reply = android.os.Parcel.obtain(); 
java.lang.String _result; 
try { 
_data.writeInterfaceToken(DESCRIPTOR); 
mRemote.transact(Stub.TRANSACTION_sayHello, _data, _reply, 0); 
_reply.readException(); 
_result = _reply.readString(); 

finally { 
_reply.recycle(); 
_data.recycle(); 

return _result; 


static final int TRANSACTION_savePersonInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 
static final int TRANSACTION_getAllPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 
static final int TRANSACTION_sayHello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); 

public void savePersonInfo(cn.com.karl.aidl.Person person) throws android.os.RemoteException; 
public java.util.List<cn.com.karl.aidl.Person> getAllPerson() throws android.os.RemoteException; 
public java.lang.String sayHello() throws android.os.RemoteException; 

package cn.com.karl.aidl;
public interface IMyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements cn.com.karl.aidl.IMyService
{
private static final java.lang.String DESCRIPTOR = "cn.com.karl.aidl.IMyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an cn.com.karl.aidl.IMyService interface,
 * generating a proxy if needed.
 */
public static cn.com.karl.aidl.IMyService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof cn.com.karl.aidl.IMyService))) {
return ((cn.com.karl.aidl.IMyService)iin);
}
return new cn.com.karl.aidl.IMyService.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_savePersonInfo:
{
data.enforceInterface(DESCRIPTOR);
cn.com.karl.aidl.Person _arg0;
if ((0!=data.readInt())) {
_arg0 = cn.com.karl.aidl.Person.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.savePersonInfo(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getAllPerson:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<cn.com.karl.aidl.Person> _result = this.getAllPerson();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_sayHello:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.sayHello();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements cn.com.karl.aidl.IMyService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public void savePersonInfo(cn.com.karl.aidl.Person person) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person!=null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_savePersonInfo, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public java.util.List<cn.com.karl.aidl.Person> getAllPerson() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<cn.com.karl.aidl.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getAllPerson, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(cn.com.karl.aidl.Person.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public java.lang.String sayHello() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_sayHello, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_savePersonInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getAllPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_sayHello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public void savePersonInfo(cn.com.karl.aidl.Person person) throws android.os.RemoteException;
public java.util.List<cn.com.karl.aidl.Person> getAllPerson() throws android.os.RemoteException;
public java.lang.String sayHello() throws android.os.RemoteException;
}
      因為sub類實現瞭Binder接口,所以以後會使用這個類。

 

         2.實現service類
          [html] public class RemoteService extends Service { 
 
    private LinkedList<Person> personList = new LinkedList<Person>(); 
     
    @Override 
    public IBinder onBind(Intent intent) { 
            return mBinder; 
    } 
 
    private final IMyService.Stub mBinder = new IMyService.Stub(){ 
 
            @Override 
            public void savePersonInfo(Person person) throws RemoteException { 
                    if (person != null){ 
                            personList.add(person); 
                    } 
            } 
 
            @Override 
            public List<Person> getAllPerson() throws RemoteException { 
                    return personList; 
            } 
 
            @Override 
            public String sayHello() throws RemoteException { 
                // TODO Auto-generated method stub 
                return "歡迎你通過AIDL訪問服務器端"; 
            } 
    }; 

public class RemoteService extends Service {

    private LinkedList<Person> personList = new LinkedList<Person>();
   
    @Override
    public IBinder onBind(Intent intent) {
            return mBinder;
    }

    private final IMyService.Stub mBinder = new IMyService.Stub(){

            @Override
            public void savePersonInfo(Person person) throws RemoteException {
                    if (person != null){
                            personList.add(person);
                    }
            }

            @Override
            public List<Person> getAllPerson() throws RemoteException {
                    return personList;
            }

   @Override
   public String sayHello() throws RemoteException {
    // TODO Auto-generated method stub
    return "歡迎你通過AIDL訪問服務器端";
   }
    };
}
         3.客戶端實現步驟:

          首先建立一個項目,把服務端的

 

 

包和類一起拷貝到客戶端項目中。因為客戶端要和服務端通信,必須要使用同一個aidl。

         然後構造客戶端的activity類:

        [html] public class RemoteClientActivity extends Activity { 
    /** Called when the activity is first created. */ 
    private TextView textHello,textPerson; 
    private IMyService myService; 
    private Button btnSave; 
    private Button btnGet; 
    private static Boolean mIsRemoteBound=false; 
    private ServiceConnection conn=new ServiceConnection() { 
         
        @Override 
        public void onServiceDisconnected(ComponentName name) { 
            // TODO Auto-generated method stub 
            myService=null; 
        } 
         
        @Override 
        public void onServiceConnected(ComponentName name, IBinder service) { 
            // TODO Auto-generated method stub 
                myService=IMyService.Stub.asInterface(service);      
            try { 
                textHello.setText(myService.sayHello()); 
            } catch (RemoteException e) { 
                // TODO Auto-generated catch block 
                e.printStackTrace(); 
            } 
        } 
    }; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
         
        textHello=(TextView) this.findViewById(R.id.textHello); 
        btnSave=(Button) this.findViewById(R.id.btnSave); 
        btnGet=(Button) this.findViewById(R.id.btnGet); 
        textPerson=(TextView) this.findViewById(R.id.textPerson); 
        if(mIsRemoteBound){ 
            unbindService(conn); 
        }else{ 
        Intent intent=new Intent("cn.com.karl.aidl.RemoteService"); 
        bindService(intent, conn, BIND_AUTO_CREATE); 
        } 
        mIsRemoteBound = !mIsRemoteBound; 
        btnSave.setOnClickListener(new OnClickListener() { 
              private int index = 0; 
 
            @Override 
            public void onClick(View v) { 
                // TODO Auto-generated method stub 
                   Person person = new Person(); 
                   indexindex = index + 1; 
                   person.setName("Person" + index); 
                   person.setAge(20); 
                   person.setTelNumber("123456");  
                   try { 
                       myService.savePersonInfo(person); 
                   } catch (RemoteException e) { 
                           e.printStackTrace(); 
                   }  
            } 
        }); 
        btnGet.setOnClickListener(new OnClickListener() { 
             
            @Override 
            public void onClick(View v) { 
                // TODO Auto-generated method stub 
                  List<Person> list = null;  
 
                  try { 
                          list = myService.getAllPerson(); 
                  } catch (RemoteException e) { 
                          e.printStackTrace(); 
                  }  
 
                  if (list != null){ 
                          StringBuilder text = new StringBuilder(); 
 
                          for(Person person : list){ 
                                  text.append("\n聯系人:"); 
                                  text.append(person.getName()); 
                                  text.append("\n             年齡:"); 
                                  text.append(person.getAge()); 
                                  text.append("\n 電話:"); 
                                  text.append(person.getTelNumber()); 
                          } 
 
                          textPerson.setText(text); 
                  }else { 
                          Toast.makeText(RemoteClientActivity.this, "得到數據出錯", 
                                          Toast.LENGTH_SHORT).show(); 
                  }  
            } 
        }); 
    } 

public class RemoteClientActivity extends Activity {
    /** Called when the activity is first created. */
 private TextView textHello,textPerson;
 private IMyService myService;
 private Button btnSave;
 private Button btnGet;
 private static Boolean mIsRemoteBound=false;
 private ServiceConnection conn=new ServiceConnection() {
  
  @Override
  public void onServiceDisconnected(ComponentName name) {
   // TODO Auto-generated method stub
   myService=null;
  }
  
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   // TODO Auto-generated method stub
    myService=IMyService.Stub.asInterface(service);  
   try {
    textHello.setText(myService.sayHello());
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        textHello=(TextView) this.findViewById(R.id.textHello);
        btnSave=(Button) this.findViewById(R.id.btnSave);
        btnGet=(Button) this.findViewById(R.id.btnGet);
        textPerson=(TextView) this.findViewById(R.id.textPerson);
        if(mIsRemoteBound){
         unbindService(conn);
        }else{
        Intent intent=new Intent("cn.com.karl.aidl.RemoteService");
        bindService(intent, conn, BIND_AUTO_CREATE);
        }
        mIsRemoteBound = !mIsRemoteBound;
        btnSave.setOnClickListener(new OnClickListener() {
           private int index = 0;

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
       Person person = new Person();
                   index = index + 1;
                   person.setName("Person" + index);
                   person.setAge(20);
                   person.setTelNumber("123456");
                   try {
                    myService.savePersonInfo(person);
                   } catch (RemoteException e) {
                           e.printStackTrace();
                   }
   }
  });
        btnGet.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
      List<Person> list = null;

                  try {
                          list = myService.getAllPerson();
                  } catch (RemoteException e) {
                          e.printStackTrace();
                  }

                  if (list != null){
                          StringBuilder text = new StringBuilder();

                          for(Person person : list){
                                  text.append("\n聯系人:");
                                  text.append(person.getName());
                                  text.append("\n             年齡:");
                                  text.append(person.getAge());
                                  text.append("\n 電話:");
                                  text.append(person.getTelNumber());
                          }

                          textPerson.setText(text);
                  }else {
                          Toast.makeText(RemoteClientActivity.this, "得到數據出錯",
                                          Toast.LENGTH_SHORT).show();
                  }
   }
  });
    }
}
              最後不要忘記註冊service:

            [html] <application 
      android:icon="@drawable/ic_launcher" 
      android:label="@string/app_name" > 
      <activity android:name=".MainActivity"> 
          <intent-filter> 
              <action android:name="android.intent.action.MAIN" /> 
 
              <category android:name="android.intent.category.LAUNCHER" /> 
          </intent-filter> 
      </activity> 
      <service android:name=".RemoteService"> 
          <intent-filter > 
              <action android:name="cn.com.karl.aidl.RemoteService"></action> 
          </intent-filter> 
      </service> 
  </application> 
  <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".RemoteService">
            <intent-filter >
                <action android:name="cn.com.karl.aidl.RemoteService"></action>
            </intent-filter>
        </service>
    </application>
           啟動service的時候使用瞭隱士意圖。

          運行服務端工程.

  服務端已經啟動,然後運行客戶端工程:

 

  OK,已經從服務端得到瞭數據,第一句話就是從服務端得到的,下面看看,傳遞對象和獲取對象與服務端。

          點擊添加聯系人,然後點擊獲取聯系人按鈕:

 

摘自 wangkuifeng0118的專欄
 

發佈留言