skywang12345

导航

统计
  • 随笔 - 278
  • 文章 - 0
  • 评论 - 1370
  • 引用 - 0
 
Android Service总结06 之AIDL

版本

版本说明

发布时间

发布人

V1.0

初始版本

2013-04-03

Skywang

       
 

1 AIDL介绍

    AIDL,即Android InterfaceDefinition Language
    Android使用AIDL来完成进程间通信(IPC),并且一般在服务需要接受不同应用多线程的请求时才需要使用AIDL;如果是同一个应用内的请求使用Binder实现即可;如果只是应用间通信而不是多线程处理的话使用Messenger,当然这两种情况也可以使用AIDL。本地进程和远程进程使用AIDL有所不同,本地进程内调用时会都在调用的线程内执行,远程进程使用是通过Service进程内一个由系统维护的线程池发出调用,所以可能是未知线程同时调用,需要注意线程安全问题。
 


2 AIDL示例

 创建AIDL服务的步骤:
(01)创建.aidl文件。        .aidl是接口文件,它定义了服务所能提供的功能。
(02)实现.aidl所定义的接口。
(03)将接口开放给其它应用程序。 

2.1 创建.aidl文件

    (01)打开eclipse,新建工程”AIDLServiceImpl”,然后在工程的“com.text”包下创建“MyAIDLInterface.aidl”文件。
    如下图:
 
    (02)编辑“MyAIDLInterface.aidl”,提供doubleValue(int val)和halfValue(int value)服务。
    “MyAIDLInterface.aidl”代码如下:
package com.test;

interface MyAIDLInterface {

    void doubleValue(int val);

    void halfValue(int val);
}
    (03)编译工程,在“gen”目录下会自动生成与“MyAIDLInterface.aidl”对应的“MyAIDLInterface.java”文件。
    如下图:

    “MyAIDLInterface.java”代码如下:
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\workout\\android\\AIDLServiceImpl\\src\\com\\test\\MyAIDLInterface.aidl
 */
package com.test;
public interface MyAIDLInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.test.MyAIDLInterface
{
private static final java.lang.String DESCRIPTOR = "com.test.MyAIDLInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.test.MyAIDLInterface interface,
 * generating a proxy if needed.
 */
public static com.test.MyAIDLInterface 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 com.test.MyAIDLInterface))) {
return ((com.test.MyAIDLInterface)iin);
}
return new com.test.MyAIDLInterface.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_doubleValue:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.doubleValue(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_halfValue:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.halfValue(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.test.MyAIDLInterface
{
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 doubleValue(int val) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(val);
mRemote.transact(Stub.TRANSACTION_doubleValue, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public void halfValue(int val) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(val);
mRemote.transact(Stub.TRANSACTION_halfValue, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_doubleValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_halfValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void doubleValue(int val) throws android.os.RemoteException;
public void halfValue(int val) throws android.os.RemoteException;
}
 

2.2 实现.aidl所定义的接口

    (04)在“com.test”包下新建文件MyAIDLService.java,并实现doubleValue(int val)和halfValue(int value)接口。
    如下图:

    MyAIDLService.java的代码如下:

package com.test;

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

public class MyAIDLService extends Service{
    private static final String TAG = "skywang-->MyAIDLService";

    private MyAIDLInterface.Stub myBinder = 
            new MyAIDLInterface.Stub() {
                
                @Override
                public void halfValue(int val) throws RemoteException {
                    Log.d(TAG, "halfValue val="+val/2);
                     
                } 
                
                @Override
                public void doubleValue(int val) throws RemoteException {
                    Log.d(TAG, "doubleValue val="+val*2);                    
                }
            };
    @Override
    public void onCreate() {        
        super.onCreate();
    }
    
    @Override
    public void onDestroy(){
        super.onDestroy();
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }
}

(05) 定义aidl对应的manifest
manifest内容如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <service android:name=".MyAIDLService" android:process=":remote"> 
            <intent-filter> 
                <action android:name="com.test.MY_AIDL_SERVICE" /> 
            </intent-filter> 
        </service>

    </application>

</manifest>
    至此,我们已经完成了.aidl服务的定义和实现。
 

2.3 将接口开放给其它应用程序

    (06)新建一个工程“AIDLServiceTest”,然后在工程的“com.skywang”包下创建AIDLServiceTest.java;
(07)然后,将MyAIDLInterface.aidl文件拷贝到AIDLServiceTest工程的“com.test”包下。
    如下图:
注意:.aidl所在的包名,必须和定义它的包名一样!(即MyAIDLInterface.aidl所在的定义它的工程的包为com.test;那么,调用MyAIDLInterface.aidl的程序,也必须把MyAIDLInterface.aidl放在com.test包下面)
 
    (08)AIDLServiceTest.java首先必须实现ServiceConnection接口。
    实现ServiceConnection接口的原因是:我们在后面调用.aidl服务的时候,必须通过bindService()去绑定服务;而bindService()需要用到ServiceConnection对象。
    实现ServiceConnection很简单,只需要实现两个接口:
       onServiceConnected    —— 连上服务的回调函数。一般在此函数中,获取服务对象。   
       onServiceDisconnected —— 断开服务的回调函数。可以直接返回null。
    ServiceConnection的实现代码如下:
  private MyAIDLInterface mBinder = null;
  private ServiceConnection mConnection = new ServiceConnection() {
    
      @Override 
      public void onServiceDisconnected(ComponentName name) {
          mBinder = null;    
      }
    
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
          Log.d(TAG, "Service connected!");
          mBinder = MyAIDLInterface.Stub.asInterface(service);
      }
  };

(09)开始访问服务之前,我们要先通过bindService()绑定服务;使用完毕之后,通过unbindService()断开服务。
AIDLServiceTest.java代码如下:
package com.skywang;

import android.app.Activity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.content.ComponentName;
import android.content.Intent;
import android.content.Context;
import android.content.ServiceConnection;
import com.test.MyAIDLInterface;

public class AIDLServiceTest extends Activity {
    private static final String TAG = "skywang-->AIDLServiceTest";

    private Button mStart = null;
    private Button mHalf = null;
    private Button mDouble = null;
    private Button mEnd = null;
    
    private MyAIDLInterface mBinder = null;
    private ServiceConnection mConnection = new ServiceConnection() {
        
        @Override 
        public void onServiceDisconnected(ComponentName name) {
            mBinder = null;    
        }
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "Service connected!");
            mBinder = MyAIDLInterface.Stub.asInterface(service);
        }
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.aidlservice_test);        

        mStart = (Button) findViewById(R.id.btStart);
        mStart.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                Log.d(TAG, "click start button");
            
                Intent intent = new Intent("com.test.MY_AIDL_SERVICE");
                boolean result = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                if (!result) {
                    mBinder = null;
                }
            }
        });


        mHalf = (Button) findViewById(R.id.btHalf);
        mHalf.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                Log.d(TAG, "click half button");

                try {
                    if (mBinder != null) {
                        mBinder.halfValue(10);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });


        mDouble = (Button) findViewById(R.id.btDouble);
        mDouble.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                Log.d(TAG, "click double button");
                
                try {
                    if (mBinder != null) {
                        mBinder.doubleValue(10);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        

        mEnd = (Button) findViewById(R.id.btEnd);
        mEnd.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                Log.d(TAG, "click end button");
                
                if (mBinder != null) {
                    unbindService(mConnection);
                    mBinder = null;
                }
            }
        });
    }
    
}

3 示例演示

    程序运行效果图:
    点击“Start”按钮,Logcat如下:
DEBUG/skywang-->AIDLServiceTest(276):click half button
DEBUG/skywang-->AIDLServiceTest(276):Service connected!
 
    点击“Half”按钮,Logcat如下:
DEBUG/skywang-->AIDLServiceTest(276):click half button
DEBUG/skywang-->MyAIDLService(285):halfValue val=5
 
    点击“Double”按钮,Logcat如下:
DEBUG/skywang-->AIDLServiceTest(276):click double button
DEBUG/skywang-->MyAIDLService(285):doubleValue val=20
 
    点击“End”按钮,Logcat如下:
DEBUG/skywang-->AIDLServiceTest(276):click end button

4 参考文献

1. Android API文档:http://developer.android.com/guide/components/aidl.html
2. Android AIDL使用详解:http://blog.csdn.net/stonecao/article/details/6425019

点击下载:源代码

更多service内容:

Android Service总结01 目录

Android Service总结02 service介绍

Android Service总结03 之被启动的服务 -- Started Service

Android Service总结04 之被绑定的服务 -- Bound Service

Android Service总结05 之IntentService

Android Service总结06 之AIDL


 

 
posted on 2013-07-03 15:38 如果天空不死 阅读(...) 评论(...) 编辑 收藏