天天看点

AIDL Android跨进程通信调用实例

AIDL的用途不多介绍了,我写了个例子是项目AB来调用项目A 的功能。根据我的例子大家可以往自己的功能需求上拓展修改。

源代码地址:http://download.csdn.net/detail/zhzhh7378/7167441

原理很简单,项目A 定义为提供服务的项目。项目AB定义为需要服务的项目。

1,首先在A工程里面定义一个AIDL文件,(可单独定义一个包方面理解)。

AIDL Android跨进程通信调用实例

这里我定义的aidl接口名字为AidlInterface后缀就是aidl这里大家注意aidl接口的写法。下面是aidl文件里面的内容

package com.test.aidl;
interface AidlInterface{
    void sendMessage(in String message,out String[] list);
    void toDoAnything();
    String getMessage();
}
           

注意必须加包名,interface类名和文件名字保持一致,这和java类的要求一样。方法体不加修饰词。sendMessage();方法体的参数 in/out我也没太多研究,有文章介绍说

in表示这个参数是调用者传递的参数out的被调用者需要传递的参数。这里掉用者就是项目AB被调用者就是项目A了。因为到时候这个aidl文件会从A拷贝到AB里面的。关于in/out

的理解不在这里研究了,最终请以官方API文档为准。

到这里aidl的第一步就完成了。

2,把aidl文件连同包一并拷贝到项目AB里面(重要的是使两个工程拥有同样的包名并且里面都包含同样的aidl文件,注意包面只要有AIDL文件就行了我里面还放了一个service文件不用拷贝了),这个步骤可以推到后面再做。因为项目A还需要做几个步骤。

     我们可以这样理解aidl就相当于接口文件,那我们项目A 是不是首先也得来实现这些接口呢。只有实现了接口才能在AB项目调用aidl里面的方法时A才能做出相应的动作。

  下面我们继续来完成项目A 的步骤。

3,既然项目A 只是用来提供服务的所以肯定是在后台运行的,肯定得有一个服务service来监听AB等实现了或者拥有相同aidl接口文件的项目的调用。所以我们在A工程里面新建一个service命名为ServiceService.这个文件我放到了和adil同一个包里面了。

package com.test.aidl;

import com.example.a.MainActivity;
import com.test.aidl.AidlInterface.Stub;

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

public class ServerService extends Service {
	private String messages="";
	private Intent intent;
	private Context c;
	private AidlInterface.Stub binder=new Stub(){

		@Override
		public void sendMessage(String message, String[] list)
				throws RemoteException {
			System.out.println("A-service-recived="+message);
			messages=message;
		}

		@Override
		public void toDoAnything() throws RemoteException {
			intent =new Intent(c,MainActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
		}

		@Override
		public String getMessage() throws RemoteException {
			return "这是A服务提供的信息";
		}
		
	};

	@Override
	public IBinder onBind(Intent arg0) {
		this.c=this;
		return binder;
	}

}
           

注意:service里面要实现aidl接口用法为,aidl接口类名我的是AidlInterface所以就是AidlInterface.Stub 关于stub的理解我引用百度搜索结果

j2ee里面的stub是这样说的..为屏蔽客户调用远程主机上的对象,必须提供某种方式来模拟本地对象,这种本地对象称为存根(stub),存根负责接收本地方法调用,并将它们委派给各自的具体实现对象
           

通过new Stub(){}来实现对aidl接口里面的方法。在service里面实现onBind();方法并返回接口的实体。这样当A项目绑定了这个service的时候就会去执行AidlInterface.Stub binder所有拥有的方法。

这里我在方法toDoAnything()方法里面让他去启动项目A 的activity。这些操作可以随便定义。

4,定义了service并且需要后台不定时提供服务所以就得在项目A的AndroidManifast.xml文件里注册service;代码如下需要注意添加action标签。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.a"
    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.example.a.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.test.aidl.ServerService"
            android:process=":remote" >
            <intent-filter>
                <action android:name="com.test.aidl.AidlInterface" />
            </intent-filter>
        </service>
    </application>

</manifest>
           

注意包名必须正确请不要省略。service里面name为服务名 process表示过程流程值为“:remote”表示远程遥控。其实就是夸进程的。添加意图intent 添加action名字为aidl接口类的路径。

5,服务有了可是没有地方开启服务,所以我们要在A首次运行的时候就开启服务不关闭。这里我在A的MainActivity里面开启服务。所以做实验的时候必须先运行项目A再去运行项目AB.开启服务的代码如下:

package com.example.a;

import com.test.aidl.AidlInterface;
import com.test.aidl.ServerService;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		bindService();
	}

	private void bindService() {
		System.out.println("a service start");
		Intent service = new Intent(this, ServerService.class);
		startService(service);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}
           

到此项目A的准备工作就结束了,这个时候A已经拥有提供远程或者跨进程的服务了。项目A 的结构很简单就需要注意4个地方定义aidl接口文件、定义服务、注册服务、开启服务。这个时候没有把aidl拷贝到AB的话就拷贝吧。

下面开始介绍项目AB:在项目AB开始之前上面的第2步骤就得完成。

AIDL Android跨进程通信调用实例

6,aidl文件拷贝过来以后请确认一下包名。AB里面要做的事情就是去调用接口的方法就行了。这里我就在AB的mainActivity里面做操作了代码如下:

package com.example.ab;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Menu;
import android.view.View;
import android.widget.Button;

import com.test.aidl.AidlInterface;

public class MainActivity extends Activity {
	private boolean onbindsuccess = false;
	// 实现接口的两个步骤
	private AidlInterface aidl = null;
	private ServiceConnection conn = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			aidl = null;
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			aidl = AidlInterface.Stub.asInterface(service);
			onbindsuccess = true;
			System.out.println("Bind success!!!" + aidl);
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		init();
	}

	/**
	 * 初始化控件
	 */
	private void init() {
		Button btn = (Button) findViewById(R.id.button1);
		Button btn2=(Button) findViewById(R.id.button2);

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		unbindService(conn);
	}

	/**绑定服务这里真正的项目要做的事情会很多 比如判断a项目是否真的存在不存在就去下载安装等操作
	 * 这里我们已经确认项目A已经安装并且服务已经开启。
	 * @param v
	 */
	public void onBind(View v) {
		System.out.println("bind click!!!");
		Intent service = new Intent(AidlInterface.class.getName());
		bindService(service, conn, BIND_AUTO_CREATE);
	}

	/**我定义的开始服务button点击事件
	 * @param v
	 */
	public void startService(View v) {
		if (!onbindsuccess) {
			System.out.println("bindservice faild");
			return;
		}
		try {
			aidl.sendMessage("从AB传递的信息", null);// 和A项目进行通信
			aidl.getMessage();// 从A项目获取信息
			aidl.toDoAnything();// 这个时候A项目的service会调用todoanything方法体里面的内容。
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
}
           

项目AB里面需要注意的是ServiceConnection 类,参考官方API service的介绍。当一个service开启运行的时候通过ServiceConnection 能直接访问此服务。

查阅官方API上面是定义了一个service 下面是通过ServiceConnection 来访问此服务

AIDL Android跨进程通信调用实例

With that done, one can now write client code that directly accesses the running service, such as:

完成所有以后,现在可以编写客户机代码,直接访问正在运行的服务,如: 

到此AB的代码已经完成,关于布局文件:

A里面我什么都没做,AB里面就在mainActivity里面加了俩按钮。完整的项目代码我已上传,不要积分大家可以下载研究学习:

http://download.csdn.net/detail/zhzhh7378/7167441