Android--使用AIDL和远程服务实现线程通信

笔记摘要:

    在Android中,每个应用都有自己的进程,当需要在不同的进程之间传递对象时,由于java不支持跨进程内存共享,因此要传递对象,需要把对象解析成操作系统能

  够理解的数据格式,以达到跨界对象访问的目的。在javaEE中,采用RMI通过序列化传递对象,在Android中,则采用AIDLAndroid Interface Definition Language

  接口定义语言)方式实现。


一、AIDL介绍

    AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现 Android设备上的两个进程间通信(IPC),AIDLIPC机制和EJB所采用

  的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。由于进程之间的通

  信信息需要双向转换,所以Android采用代理类在背后实现了信息的双向转换,代理类由Android编译器生成,对开发人员来说是透明的。

 

所以我们在定义服务端的时候需要定义一个AIDL类型的文件指定一种协议来确保服务端和客户端的通信。


二、创建AIDL协议的方式及注意事项:

  在B应用中创建“aidl文件,aidl文件的定义和接口的定义很类似,所以我们可以新建一个接口StudentQuery,在接口中定义一些方法后,修改该文件类型为aidl

 即可完成该aidl文件的创建。


编写AIDL文件时,需要注意的事项:

1、接口名和aidl文件名相同。

2、接口和方法前不用加访问权限修饰符publicprivateprotected,也不能加finalstatic

3、Aidl默认支持的类型包括java基本类型(intlongboolean等)和(StringListMapCharSequence),使用这些类型不需要import声明。对于ListMap中的元素类型必须是aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口、

4、自定义类型和aidl生成的其它接口类型在aidl描述文件中,应该显示import,即便在该类和定义的包在同一个包中。

5、在aidl文件中所有的非java基本类型参数必须加上inoutinout标记,以指明参数是输入参数、输出参数还是输入参数。

6、Java原始类型默认的标记为in,不能为其它标记。



程序中需要注意:

  当完成aidl文件创建后,eclipse会自动在项目中的gen目录中同步生成StudentQuery.java接口文件。接口文件生成一个Stub的抽象类,里面包括aidl定义的方法,

 还包括一些其他辅助方法。值得注意的是asInterfaceIbinder iBinder)返回接口类型的实例,对于远程服务调用,远程服务返回给客户端的对象为代理对象,

 客户端在onServiceConnected(ComponentName name,IBinder service)方法引用该对象时,不能直接强转成接口类型的实例,而应该使用asInterfaceIBinder iBinder

 进行类型转换。


三、效果图




四、代码体现

  

  说明:

  这里通过在一个Android客户端进程中向Android服务端发送业务请求,服务端进行处理后,返回给客户端结果。和本地服务一样,它们之间同样

  通过Binder来进行通信

4.1 服务端


AIDL文件

package cn.xushuai.aidl;

//AIDL描述,用于编译器生成通讯协议
interface StudentQuery {
	String queryStudent(int number);
}


注册业务类,同时定义一个激活名,用于客户端调用该业务类

<service android:name=".StudentQueryService">
	    <!-- 采用隐式激活服务,激活名称为cn.xushuai.student.query -->
	    <intent-filter >
	        <action android:name="cn.xushuai.student.query"/>
	    </intent-filter>
	</service>



业务类

  说明:

      这里的Binder继承的是gen根目录下,AIDL文件生成的相应的文件中的StudentQuery接口的内部类Stub,它已经继承了Binder对象,

      这样做的目的就是为了让该服务具有远程通讯能力。

      但是这里的binder对象是一个代理。

package cn.xushuai.remote.service;

import cn.xushuai.aidl.StudentQuery.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class StudentQueryService extends Service {
	private String[] names = {"张三","李四","王五"};
	private IBinder binder = new StudentQueryBinder();
	@Override
	public IBinder onBind(Intent intent) {
		return binder;	//返回给客户端一个具有远程通讯能力的binder对象,其实是一个代理
	}
	
	private String query(int number){
		if(number > 0 && number < 4){
			return names[number-1];
		}
		return null;
	}
	
	//为了让该服务具有远程通讯的能力,所以继承编译器生成的通讯类中的Stub,它继承自Binder
	private final class StudentQueryBinder extends Stub{

		public String queryStudent(int number) throws RemoteException {
			return query(number);
		}
		
	}
}


4.2 客户端


同样在客户端也需要相同的AIDL文件

package cn.xushuai.aidl;

//AIDL描述,用于编译器生成通讯协议
interface StudentQuery {
	String queryStudent(int number);
}


客户端页面代码

 <EditText 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/studentno"
        />
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/studentno"
        android:id="@+id/button"
        android:text="@string/button"
        />
	<TextView 
	    android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/button"
        android:id="@+id/resultView"
	    />



客户端的业务类

package cn.xushuai.remoteservice.client;

import cn.xushuai.aidl.StudentQuery;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class RemoteServiceClient extends Activity {
	private EditText studentno;
	private TextView resultView;
	private StudentServiceConnection conn = new StudentServiceConnection();
	private StudentQuery studentQuery;
    
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_remote_service_client);
        
        studentno = (EditText)this.findViewById(R.id.studentno);
        Button button = (Button) this.findViewById(R.id.button);
        resultView = (TextView) this.findViewById(R.id.resultView);
        button.setOnClickListener(new ButtonClickListener());
        
        Intent service = new Intent("cn.xushuai.student.query");
        bindService(service, conn, BIND_AUTO_CREATE);//绑定后自动创建服务
    }
	
    //实现一个服务连接对象
    private class StudentServiceConnection implements ServiceConnection{

		public void onServiceConnected(ComponentName name, IBinder service) {
			//将返回的binder代理转换为接口对象
			studentQuery = StudentQuery.Stub.asInterface(service);
		}
		public void onServiceDisconnected(ComponentName name) {
			studentQuery = null;
		}
    	
    }
    
    //当Activity摧毁的时候,解除与服务的绑定
    @Override
	protected void onDestroy() {
    	unbindService(conn);
		super.onDestroy();
	}

	private final class ButtonClickListener implements View.OnClickListener{

		public void onClick(View v) {
			String number = studentno.getText().toString();
			int num = Integer.valueOf(number);
			try {
				String name = studentQuery.queryStudent(num);
				resultView.setText(name);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
    	
    }
}




posted @ 2013-01-31 15:06  积小流,成江海  阅读(344)  评论(0编辑  收藏  举报