AIDL服务

本文详细介绍了 Android 进程间通信 (IPC) 的核心机制 AIDL 的使用方法及注意事项,通过两个实例展示了主进程如何调用 Service 进程的服务以及 Service 进程如何回调主进程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android的IPC有四种,详见:http://blog.youkuaiyun.com/habbyge/article/details/17796345

AIDL学习文档:http://developer.android.com/guide/components/aidl.html#PassingObjects

重点:AIDL应该注意的事项:

1. AIDL文件的inteface中的成员函数的参数

(1)参数是基本数据类型,则默认是in方向的,可以没有限制的直接使用(包括String);

(2)参数是Java支持的引用类型,必须指明in/out/inout方向,也可以直接使用;

(3)参数是Android中的引用类型,则必须是可以序列化的(Parcelable),且必须指明in/out/inout方向,也就是说,如果Android里的类对象时Parcelable的,才可以传入,不是Parcelable的,不能传入,需用其他方法解决(AIDL接口方法);

(4)对于自定义的类TestData.java,需要另外增加一个AIDL文件TestData.aidl,首先该自定义类TestData.java必须实现Parcelable,然后再写一个声明该类的声明文件(TestData.aidl),该声明文件(TestData.aidl)用于告诉引用该类的aidl文件,此类遵守Parcelable协议,可以在AIDL中使用(其实就是在TestData.aidl文件中声明如下:parcelable TestData,即可):

1) TestData.java

public class TestData implements Parcelable {

    private String name = "";

    public TestData() {
    }

    public String getName() {
        return name;
    }

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


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

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

    protected TestData(Parcel in) {
        this.name = in.readString();
    }

    public static final Parcelable.Creator<TestData> CREATOR = new Parcelable.Creator<TestData>() {
        public TestData createFromParcel(Parcel source) {
            return new TestData(source);
        }

        public TestData[] newArray(int size) {
            return new TestData[size];
        }
    };
}
2) TestData.aidl

package com.tencent.qqpim.apps.photo.sdk.aidl;

parcelable TestData;
3) test.aidl

package com.tencent.qqpim.apps.photo.sdk.aidl;

import com.tencent.qqpim.apps.photo.sdk.aidl.TestData;

interface test {
    void fn1(int x, String y);
    List<String> fn2(in TestData td);
}

必须为AIDL文件中的接口成员函数的引用参数类型指明读写方向,这样可以做到优化,因为传输类对象到AIDL的时候,AIDL需要对类对象进行Parcelable(序列化),指明in/out/inout可以做到只写或只读或读写对象,省时。所有的基本数据类型都是默认in的,可以不用显示指定,但是所有非基本类型(对象引用)都必须是Parcelable、且必须显示指定in/out/inout。

【AIDL文件是主进程和Service进程的接口】

【AIDL文件中的接口函数如果是在Service进程中实现,则是在Service进程中执行,并且是为了让主进程调用】

【AIDL文件中的接口函数如果是在主进程中实现,则是在主进程中执行,并且是为了让Service进程调用】

2. Service进程回调主进程中的代码(以更新Activity)

AIDL文件可以有多个,AIDL文件可以在Service进程中运行,也可以在主进程中运行,主要是看改AIDL接口是在哪里实现的,如果在Service进程中实现,则是在Service中运行的;如果是在主进程中实现的,则是在主进程中运行;AIDL全称是Andorid接口定义语言,也就是说只是在AIDL文件中定义进程间都可以使用的接口,具体是在哪个进程中运行,主要是看在哪个进程中实现这些接口;在主进程中实现的AIDL接口,主要是让Service进程来调用(回调)主进程中接口的,在Service进程中是实现的接口,主要是让主进程调用(回调)Service进程中接口的。

AIDL文件接口如果是主进程中实现,则表示该接口是在主进程中运行的,用来让Service进程来调用的;如果是在Service进程中实现,则表示是在Service线程中执行,用来让主进程来调用。

例子如下:


(1)MainActivity.class

package com.habby.test;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.widget.TextView;

import com.example.com.habby.test.R;
import com.habby.test.aidl.IRemoteCallback;
import com.habby.test.aidl.IRemoteService;

/**
 * 主进程
 * 让Service进程回调主进程中的修改界面的回调函数
 */
public class MainActivity extends Activity {
	private final String TAG = "MainActivity";
	
	private TextView mNameTv;	// 被更改的View
	
	private IRemoteService mRemoteService;	// Service进程中执行的远程接口
	private static final int sCHANGE_VIEW_SUCCESS = 1;
	
	/**
	 * 主进程中执行的接口,更新主进程中的界面。
	 */
	public IRemoteCallback.Stub mCallback = new IRemoteCallback.Stub() {
		@Override
		public void changeView() throws RemoteException {
			Log.d(TAG, "activity pid = " + Process.myPid());
			Message.obtain(mHandler, sCHANGE_VIEW_SUCCESS).sendToTarget();
		}
	};
	
	/**
	 * 当主进程的Activity连接上Service进程中的Service后,回调该对象
	 */
	private ServiceConnection mConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {	// 连接断开
			Log.d(TAG, "onServiceDisconnected()");
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {	// 连接成功
			
			// 获得Service进程中的远程接口
			mRemoteService = IRemoteService.Stub.asInterface(service);
			if (mRemoteService != null) {
				try {
					/**
					 * 主进程获取Service进程中的数据、执行Service进程中的方法;
					 */
					mRemoteService.getPid();
					mRemoteService.basicTypes(1, 2L, true, 2.0f, 2.0D, "I love Merry");
					
					/**
					 * 主进程把主进程中的更改View的接口(IRemoteCallback.aidl)传入Service进程,
					 * 让Service进程可以更改主进程中的数据(View)。
					 */
					mRemoteService.setCallback(mCallback);
				} catch (android.os.RemoteException e) {
					e.printStackTrace();
				}
			}
		}
	};
	
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case sCHANGE_VIEW_SUCCESS:
				mNameTv.setText(R.string.name);
				break;

			default:
				break;
			}
	    }
	};
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate()");
        setContentView(R.layout.activity_main);
        mNameTv = (TextView) findViewById(R.id.name);
        
        Log.d(TAG, "pid = " + Process.myPid());
        
        // 绑定服务
        Intent intent = new Intent(this, AIDLService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
    	Log.d(TAG, "onDestroy()");
    	unbindService(mConnection);	// 取消服务
    	super.onDestroy();
    }
}
(2)AIDLService.class

package com.habby.test;

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

import com.habby.test.aidl.IRemoteCallback;
import com.habby.test.aidl.IRemoteService;
// Service进程
public class AIDLService extends Service {
	private final String TAG = "AIDLService";
	
	private IRemoteCallback mViewCallback;
	
	public class RemoteService extends IRemoteService.Stub {
    	@Override
    	public int getPid() {
    		int pid = Process.myPid();
    		Log.d(TAG, 	"AIDLService pid = " + pid);
    		return pid;
    	}
    	
    	@Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, 
        		float aFloat, double aDouble, String aString) {
    		
        	Log.d(TAG, "/" + anInt + "/" + aLong + "/" + aBoolean + "/" + 
        			aFloat + "/" + aDouble + "/" + aString + "/");
        }
    	
    	@Override
    	public void setCallback(IRemoteCallback callback) {
    		Log.d(TAG, "setCallback()");
    		try {
    			callback.changeView();
    		} catch (android.os.RemoteException e) {
    			e.printStackTrace();
    		}
    		
    		mViewCallback = callback;
    	}
    }
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG, "onCreate()");
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind()");
		return new RemoteService();
	}
	
	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy()");
		super.onDestroy();
    }
}
(3)IRemoteService.aidl,Service进程中的调用,在Service进程中实现

package com.habby.test.aidl;

import com.habby.test.aidl.IRemoteCallback;

interface IRemoteService {
    int getPid();
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 
            double aDouble, String aString);
    void setCallback(IRemoteCallback callback);
}
(4)IRemoteCallback.aidl,主进程中的调用,在主进程中实现

package com.habby.test.aidl;

interface IRemoteCallback {
    void changeView();
}

(5)AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.com.habby.test"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <activity
            android:name="com.habby.test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
        <service
            android:name="com.habby.test.AIDLService"
            android:process="com.habby.remote" />
    </application>

</manifest>

3. 主进程调用Service进程的代码(Service进程提供的服务)

例子如下:


(1)RemoteCallExampleActivity.java

package com.habby.remote;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;

import com.habby.remote.aidl.IRemoteCall;

public class RemoteCallExampleActivity extends Activity {
	private IRemoteCall iRemoteCall;	// aidl服务接口
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// 启动Service
		Intent remotecall = new Intent(this, RemoteCallService.class);
		bindService(remotecall, new ServiceConnection() {
			@Override
			public void onServiceDisconnected(ComponentName name) {
			}
			
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				iRemoteCall = IRemoteCall.Stub.asInterface(service);
				try {
					String args = "I love Merry !";
					iRemoteCall.setListener(args);
				} catch(RemoteException e) {
					e.printStackTrace();
				}
			}
		}, Context.BIND_AUTO_CREATE);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
	}
}
(2)RemoteCallService.java
package com.habby.remote;

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

import com.habby.remote.aidl.IRemoteCall;

public class RemoteCallService extends Service {
	private final String TAG = "Habby";
	
	/**
	 * Service实现的aidl策略
	 */
	public class RemoteCall extends IRemoteCall.Stub {
		@Override
		public void setListener(String listener) {
			Log.i(TAG, "Service RemoteCall() setListener()" + listener);
		}
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return new RemoteCall();
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(TAG,"Service onCreate()");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG,"Service onStartCommand()");
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy() {
		Log.d(TAG,"Service onDestroy()");
		super.onDestroy();
	}
}
(3)IRemoteCall.aidl,在包com.habby.remote.aidl中:

package com.habby.remote.aidl;

interface IRemoteCall {
	void setListener(String listener);
}
(4)AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.com.habby.remote"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <activity
            android:name="com.habby.remote.RemoteCallExampleActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <service
            android:name="com.habby.remote.RemoteCallService"
            android:process="com.habby.subprocess" > <!-- 把Service作为一个的进程 -->
            <intent-filter>
                <action android:name="com.habby.remote.RemoteCallService.action" />
            </intent-filter>
        </service>
    </application>

</manifest>

注意:在做类似项目的过程中,遇到一个问题值得注意:

Service的onBind(),在没有调用unbindService()的时候,无论调用多少次bindService()该onBind()都只会被调用一次(但是ServiceConnection会每次都被调用),且是在第一次bindSerivce()的时候被调用,也就说只绑定一次(前提是没有调用unbindService())。

<think>在Android开发中,AIDL(Android Interface Definition Language)用于进程间通信(IPC)。通常情况下,我们通过绑定服务(bindService)来获取AIDL接口的实例,然后直接调用其方法。但有时候,我们可能需要通过反射的方式来调用AIDL服务,例如当我们无法直接依赖AIDL接口的类文件时。 反射调用AIDL服务的步骤大致如下: 1. 获取服务的IBinder对象(可以通过ServiceConnection回调获取,或者通过其他方式如ServiceManager获取系统服务)。 2. 通过反射获取AIDL接口的Stub类(通常为内部类,如IMyAidlInterface.Stub)。 3. 使用Stub类的asInterface方法将IBinder对象转换为AIDL接口对象。 注意:由于AIDL的Stub类通常是一个抽象类,并且是AIDL接口的私有实现,因此我们需要通过反射来获取它。 下面是一个示例,假设我们有一个AIDL接口名为`IMyAidlInterface`,其包名为`com.example.aidl`。我们将通过反射来调用它。 步骤: 1. 绑定服务,获取IBinder对象(这里假设你已经通过某种方式获取到了IBinder对象,例如通过绑定服务)。 2. 使用反射获取`com.example.aidl.IMyAidlInterface$Stub`类(注意Stub是IMyAidlInterface的内部类)。 3. 调用Stub类的`asInterface`静态方法,传入IBinder对象,得到AIDL接口的代理对象。 4. 通过反射调用接口的方法。 由于我们无法直接访问IMyAidlInterface类,因此我们需要知道方法的名称和参数类型,以便通过反射调用。 下面是一个代码示例: ```java import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class AidlReflectionHelper { private IBinder mBinder; private Object mAidlInterface; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinder = service; try { // 获取Stub类的Class对象 Class<?> stubClass = Class.forName("com.example.aidl.IMyAidlInterface$Stub"); // 获取asInterface方法 Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class); // 调用asInterface方法,将IBinder转换为AIDL接口对象 mAidlInterface = asInterfaceMethod.invoke(null, mBinder); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mBinder = null; mAidlInterface = null; } }; public void bindService(Context context) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.serviceapp", "com.example.serviceapp.MyAidlService")); context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } public void unbindService(Context context) { context.unbindService(mConnection); } // 通过反射调用AIDL方法 public void callAidlMethod() { if (mAidlInterface == null) { return; } try { // 获取AIDL接口中的方法,假设有一个方法名为doSomething,参数为int,返回值为String Method method = mAidlInterface.getClass().getMethod("doSomething", int.class); String result = (String) method.invoke(mAidlInterface, 123); System.out.println("Result: " + result); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } } ``` 解释: 1. 在`ServiceConnection`的`onServiceConnected`回调中,我们获取到了服务端返回的IBinder对象。 2. 通过反射加载`IMyAidlInterface.Stub`类(注意内部类的表示方式为`IMyAidlInterface$Stub`)。 3. 获取`Stub`类的静态方法`asInterface`,该方法需要一个IBinder参数。 4. 调用`asInterface`方法,传入IBinder对象,得到AIDL接口的代理对象(即`mAidlInterface`)。 5. 当需要调用AIDL接口中的方法时,我们通过反射获取该接口中对应的方法(需要知道方法名和参数类型),然后使用`invoke`来调用。 注意事项: - 使用反射调用AIDL服务需要知道AIDL接口的完整类名和方法签名(包括包名)。 - 由于使用了反射,代码可读性和可维护性较差,且容易出错。因此,除非必要(如无法直接依赖AIDL接口的类),否则不建议使用反射。 - 反射调用会带来一定的性能开销。 - 在调用方法时,如果方法抛出RemoteException,反射调用会抛出InvocationTargetException,其内部包裹了RemoteException,需要额外处理。 另外,对于系统服务,我们可以通过`ServiceManager`获取IBinder,然后使用反射调用。但非系统服务需要先绑定服务获取IBinder。 相关问题: 1. 如何通过反射调用系统服务(如ActivityManagerService)? 2. AIDL的工作原理是什么? 3. 在使用反射调用AIDL方法时,如何处理可能抛出的异常? 4. 除了反射,还有哪些方式可以在没有AIDL接口类的情况下进行进程间通信?</think>### 反射调用 AIDL 服务详解 在 Android 开发中,通过反射调用 AIDL 服务适用于无法直接依赖 AIDL 接口定义的特殊场景(如插件化开发)。以下是完整实现方案: #### 核心步骤 1. **获取服务端 IBinder 对象** 2. **反射加载 AIDL Stub 类** 3. **通过 `asInterface()` 创建代理对象** 4. **反射调用 AIDL 接口方法** #### 完整代码实现 ```java // 反射工具类 public class AidlReflectionInvoker { private static final String TAG = "AidlReflectionInvoker"; private IBinder mRemoteBinder; private Object mAidlProxy; // 绑定服务获取 IBinder public void bindService(Context context, String packageName, String serviceName) { Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, serviceName)); context.bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mRemoteBinder = service; createAidlProxy("com.example.IMyAidlInterface"); } @Override public void onServiceDisconnected(ComponentName name) { mRemoteBinder = null; mAidlProxy = null; } }, Context.BIND_AUTO_CREATE); } // 创建 AIDL 代理对象 private void createAidlProxy(String aidlInterfaceName) { try { // 1. 加载 Stub 类 (IMyAidlInterface$Stub) Class<?> stubClass = Class.forName(aidlInterfaceName + "$Stub"); // 2. 获取 asInterface 方法 Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class); // 3. 创建代理对象 mAidlProxy = asInterfaceMethod.invoke(null, mRemoteBinder); } catch (Exception e) { Log.e(TAG, "Create proxy failed", e); } } // 反射调用 AIDL 方法 public String invokeAidlMethod(String methodName, int arg) { if (mAidlProxy == null) { Log.e(TAG, "AIDL proxy not initialized"); return null; } try { // 1. 获取方法对象 (根据实际参数类型调整) Method targetMethod = mAidlProxy.getClass() .getMethod(methodName, int.class); // 2. 调用方法并返回结果 return (String) targetMethod.invoke(mAidlProxy, arg); } catch (Exception e) { Log.e(TAG, "Invoke method failed", e); return null; } } } ``` #### 关键代码解释 1. **Stub 类加载** `Class.forName("com.example.IMyAidlInterface$Stub")` 动态加载 AIDL 生成的 Stub 类,这是 AIDL 的 IPC 核心实现。 2. **asInterface() 方法** ```java Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class); mAidlProxy = asInterfaceMethod.invoke(null, mRemoteBinder); ``` - 通过反射获取 `Stub.asInterface()` 静态方法 - 将服务端返回的 `IBinder` 转换为本地代理对象 - `invoke()` 的 `null` 参数表示调用静态方法 3. **方法调用** ```java Method targetMethod = mAidlProxy.getClass().getMethod("doSomething", int.class); String result = (String) targetMethod.invoke(mAidlProxy, 123); ``` - `getMethod()` 根据方法名和参数类型定位目标方法 - `invoke()` 执行远程调用并返回结果 #### 注意事项 1. **跨进程异常处理** 所有反射调用必须捕获以下异常: - `RemoteException`:IPC 通信失败 - `InvocationTargetException`:被调用方法内部异常 - `ClassNotFoundException`:AIDL 接口类不存在 2. **类型匹配** 方法参数和返回值类型必须与 AIDL 接口定义严格一致: ```aidl // AIDL 定义示例 interface IMyAidlInterface { String doSomething(int input); } ``` 3. **性能影响** 反射调用比直接调用慢 3-4 倍,建议: - 缓存 `Method` 对象 - 避免高频调用 4. **权限管理** 如果服务声明了权限,调用前需检查权限: ```java if (context.checkPermission("com.example.PERMISSION", android.os.Process.myPid(), android.os.Process.myUid()) == PERMISSION_GRANTED) { // 执行调用 } ``` #### 典型应用场景 1. 插件化框架调用主 App 服务 2. 热修复过程中临时调用服务 3. SDK 需要兼容不同版本的服务接口 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值