Android开发 Activity通过AIDL与Service通讯 实现进程间通讯

AIDL全称Android Interface Definition Language,即Android接口定义语言,通过它可以在进程间通讯,今天的例子演示的是在Activity与Service间通讯。
程序结构:
包com.example.aidl中有五个文件
AIDLService.java: Service
MainActivity.java: 第一个Activity,在这里启动Service,并与之通讯
People.java: JavaBean,两字段,name,age,一方法say
SecondActivity.java: 第二个Activity,与在MainActivity中启动的AIDLService通讯
PeopleAIDL.aidl AIDL定义文件,其实就是一个Interface,但扩展名不是java,添加这个文件后,在gen目录下会自动生成PeopleAIDL.java.
本例使用了AndroidAnnotations框架,没接触过的童鞋可能会看不太懂,但其实这个框架也蛮简单的,参考前文AndroidAnnotations框架@Ebean,@RootContext,@Background,@UiThread,@AfterInject,@AfterTextChange标签的使用方法,一看就明白。

布局:main_activity.xml:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="绑服务" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="22dp"
        android:layout_toRightOf="@+id/button1"
        android:text="setName" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/textView1"
        android:text="setAge" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="16dp"
        android:text="say" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/button4"
        android:layout_alignLeft="@+id/button2"
        android:text="SecondActivity" />

</RelativeLayout>

second_activity.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bind Service" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Say" />

</LinearLayout>

接下来是Java代码:
People.java:


package com.example.aidl;

import android.content.Context;
import android.widget.Toast;

import com.googlecode.androidannotations.annotations.EBean;
import com.googlecode.androidannotations.annotations.RootContext;

@EBean
public class People {
	@RootContext
	Context context;
	String name;
	int age;
	public void say()
	{
		Toast.makeText(context, "I'm "+name+" I "+age+" years old.", Toast.LENGTH_LONG).show();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

用了androidannotations的@RootContext,上面的context会自动取到,不会为空。
PeopleAIDL.aidl:


package com.example.aidl;

interface PeopleAIDL {
	void setAge(int age);
	void setName(String name);
	void say();
}

网上的文章都称这个文件要放在包目录下,如果是多个包,到底是AndroidManifest.xml中声明的package还是其他包,没测试。保存后,ADT会在gen下的同名包下生成PeopleAIDL.java.
AIDLService.java:


package com.example.aidl;

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

import com.googlecode.androidannotations.annotations.Bean;
import com.googlecode.androidannotations.annotations.EService;

@EService
public class AIDLService extends Service {
	@Bean
	People people=new People();
	PeopleAIDL.Stub stub=new PeopleAIDL.Stub() {
		//下面的方法都是供远程调用的
		public void setName(String name) throws RemoteException {
			// TODO Auto-generated method stub
			people.setName(name);
		}
		
		public void setAge(int age) throws RemoteException {
			// TODO Auto-generated method stub
			people.setAge(age);
		}
		
		public void say() throws RemoteException {
			// TODO Auto-generated method stub
			people.say();
		}
	};
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		//onBind方法要返回PeopleAIDL.Stub
		return stub;
	}
	
}

MainActivity.java:


package com.example.aidl;

import android.app.Activity;
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 android.widget.Button;

import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;

@EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
	PeopleAIDL peopleAIDL;
	@ViewById
	Button button1,button2,button3,button4,button5;

	ServiceConnection conn = new ServiceConnection(){
		public void onServiceConnected(ComponentName className, IBinder service) {
			//服务绑定成功,绑定动作好像是异步的
			peopleAIDL=PeopleAIDL.Stub.asInterface(service);
		}

		public void onServiceDisconnected(ComponentName className) {
		
		}
	};
	//下面是几个按钮的点击事件
	@Click
	void button1()
	{
		//绑定启动服务
		bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
		startService(new Intent(this, AIDLService_.class));
	}
	@Click
	void button2()
	{
		try {
			peopleAIDL.setName("zhangshan");
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Click
	void button3()
	{
		try {
			peopleAIDL.setAge(23);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Click
	void button4()
	{
		try {
			peopleAIDL.say();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Click
	void button5()
	{
		//SecondActivity后加_是因为用了androidannotations
		Intent intent=new Intent(this,SecondActivity_.class);
		startActivity(intent);
	}
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		//退出时必须unbindService
		unbindService(conn);
		//如果Service仍需要在后台运行,不需要下面的这句
		stopService(new Intent(this, AIDLService_.class));
	}
}

SecondActivity.java:


package com.example.aidl;

import android.app.Activity;
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 android.widget.Button;

import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;

@EActivity(R.layout.second_activity)
public class SecondActivity extends Activity {
	PeopleAIDL peopleAIDL;
	@ViewById
	Button button1,button2;
	
	private ServiceConnection conn = new ServiceConnection(){
		public void onServiceConnected(ComponentName className, IBinder service) {
			peopleAIDL=PeopleAIDL.Stub.asInterface(service);
		}

		public void onServiceDisconnected(ComponentName className) {
		}
	};
	
	@Click
	void button1()
	{
		bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
               //如果调用的是另一个应用的Service,使用new Intent("Service的Action");
	}
	@Click
	void button2()
	{
		try {
			peopleAIDL.say();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

若调用的是另一个应用的Service,需要那个应用声明Service时加上Action,如:


        <service android:name=".service.GCService" >
            <intent-filter>
                <action android:name="com.pocketdigi.service.GCservice" />
            </intent-filter>
        </service>

在bindService的Intent里传入这个Action.
需要注意的是,两个应用的AIDL文件必须完全一致,包括在包名。

© 2012, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记