android的aidl机制案例

这段时间在学习android,结果碰到了教学视频中经常提到和使用aidl,随后在网上找了一些资料,写了一些案例来分析分析,假如我写的和解释的有些偏差,希望能被大家指点出来纠正自己的拙见。<p><span style="font-size:12px;">AIDL是一个接口描述文件,用于实现Android平台上面的RPC,aapt在编译的时候会自动根据规则生成用于IPC的接口和对象,而作为使用者只需要:1.在服务端Service实现接口;2. 在客户端bindService,onServiceConnected时获取接口对象。这里的接口都是AIDL中描述的接口,其他的细节则在由AIDL生成的同名源码文件中</span></p><p><span style="font-size:12px;">我所实现的案例是从服务端获取一个书本的信息:</span></p>

package com.edify.bluenfcserver.myservice;

import java.util.Date;

import android.annotation.SuppressLint;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * @Description 写一个实体类步骤:
 * 1. 实现Pracelable接口
 * 2. 需要定义一个Parcelable.Creator CREATOR对象
 * 3. 同时要建立一个aidl文件
  * @Author monkey
  * @Date 2014年9月4日下午5:22:02
 */
@SuppressLint("ParcelCreator")
public class BookInfo implements Parcelable {
	private int id;
	private String name;
	private String author;
	private float price;
	private Date product;

	public BookInfo(Parcel in) {

	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

	public Date getProduct() {
		return product;
	}

	public void setProduct(Date product) {
		this.product = product;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public float getPrice() {
		return price;
	}

	public void setPrice(float price) {
		this.price = price;
	}

	public BookInfo(int id, String name, String author, float price, Date product) {
		super();
		this.id = id;
		this.name = name;
		this.author = author;
		this.price = price;
		this.product = product;
	}

	@Override
	public int describeContents() {
		return 0;
	}
	/**
	 * 将对象序列号
	 * dest 就是对象即将写入的目的对象
	 * flags 有关对象序列号的方式的标识
	 * 这里要注意,写入的顺序要和在createFromParcel方法中读出的顺序完全相同。例如这里先写入的为name,
	 * 那么在createFromParcel就要先读name
	 */
	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(id);
		dest.writeString(name);
		dest.writeString(author);
		dest.writeFloat(price);
		dest.writeValue(product);// 写一个date类型的数据
	}
	/**
	 * 在想要进行序列号传递的实体类内部一定要声明该常量。常量名只能是CREATOR,类型也必须是
	 * Parcelable.Creator<T>
	 */
	public static final Parcelable.Creator<BookInfo> CREATOR = new Parcelable.Creator<BookInfo>() {
		/***
		 * 根据序列号的Parcel对象,反序列号为原本的实体对象
		 * 读出顺序要和writeToParcel的写入顺序相同
		 */
		public BookInfo createFromParcel(Parcel in) {
			int id = in.readInt();
			String name = in.readString();
			String author = in.readString();
			float price = in.readFloat();
			Date product = (Date) in.readValue(this.getClass().getClassLoader());
			return new BookInfo(id, name, author, price, product);
		}

		public BookInfo[] newArray(int size) {
			return new BookInfo[size];
		}
	};

}

客户端的代码:

package com.edify.bluenfc;

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 android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.edify.bluenfcserver.Beauty;
import com.edify.bluenfcserver.RemoteBeauty;
import com.edify.bluenfcserver.myservice.BookInfo;
import com.edify.bluenfcserver.myservice.MyRemoteBookInfo;
import com.edify.bluenfcserver.myservice.MyRemoteBookInfo.Stub;

public class MainActivity extends Activity implements OnClickListener {
	TextView textView;
	Button button;
	String actionName = "com.edify.bluenfcserver.remoteservice";
	String actionName2 = "com.edify.bluenfcserver.myservice.myRemoteService";
	RemoteBeauty remoteBeauty;
	private MyRemoteBookInfo myRemoteBookInfo;
	private TextView textView2;
	private View button2;

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

		textView = (TextView) findViewById(R.id.textView1);
		textView2 = (TextView) findViewById(R.id.textView2);
		button = (Button) findViewById(R.id.button1);
		button2 = (Button) findViewById(R.id.button2);
		button.setOnClickListener(this);
		button2.setOnClickListener(this);
	}

	// service.queryLocalInterface("com.edify.bluenfcserver.RemoteBeauty");
	// getPackageManager():提供了方法可以对清单文件中的配置进行查询
	private class MyServiceConnection implements ServiceConnection {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.i("通知", "链接成功!");
			remoteBeauty = RemoteBeauty.Stub.asInterface(service);
			try {
				Beauty beauty = remoteBeauty.getBeauty();
				textView.setText("美女  姓名:" + beauty.getName() + "  年龄:" + beauty.getAge() + " 性别:" + beauty.getSex());

			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {

		}

	}

	MyServiceConnection connection = new MyServiceConnection();

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			Intent intent = new Intent(actionName);
			bindService(intent, connection, Context.BIND_AUTO_CREATE);
			break;

		case R.id.button2:
			Intent intent2 = new Intent(actionName2);

			// 建立连接:第一步,向服务端发请求
			bindService(intent2, new MyBookInfoServiceConnection(), Context.BIND_AUTO_CREATE);
			break;
		}
	}

	// 建立与服务器链接对象,桥梁
	private class MyBookInfoServiceConnection implements ServiceConnection {
		// 建立连接:第三步
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// 判断是否是同一个进程内的进行通信,假如是那么返回的是同一个对象,如果不是那么返回的是代理对象
			/**
			 * 假如是一个进程内通信,就没有必要进行aidl的机制来处理了
			 * 这实际上就是判断此通讯是在同一进程中,还是跨进程,因为同一进程传回的对象是Service
			 * .onBind()所返回的对象,而此对象必然实现了接口
			 * (要不然搞毛啊!)。所以,如果仅是在同一个进程之中,不会走Binder进程IPC
			 * ,而是直接返回Service所提供的对象,直接调用其方法,因此也就不会有对象必须Parcelable的限制!
			 * 也就是说,当在同一个进程中时AIDL实际上变成了这样的:
			 * 也就是说它是直接返回了Service.onBind()的对象,这其实跟前面提到的第一种方式
			 * :直接实现Binder对象的方式是一样一样的
			 * ,其他的代码全是多余的。因此,如前面建议的,如果仅是在同一个进程中,就直接使用Binder就好了,没有必要创建AIDL文件。
			 * 当在不同的进程中时
			 * ,客户端Stub.asInterface会返回一个Stub.Proxy对象,调用其上的print方法。而服务端仅会执行Stub
			 * .onTransact()方法,然后就调到Service的print方法了。
			 * 当跨进程的时候,就要使用Binder对象的IPC相关的方法和机制
			 * 。客户端需要实现Binder.transact()方法来执行远程的一个方法
			 * ,这是给客户端来使用;而服务端则需要实现Binder.onTransact
			 * ()来响应客户端所请求的方法。对于上层使用者来说,用transact
			 * ()把函数的信息(参数,标识和开关)发送出去,剩下的就是Binder的工作了
			 * ,内部还有大量的细节,但是最终会调用到服务端Binder的onTransact
			 * ()方法,这里识别出函数的标识,然后调用具体的实现,再传回返回值,这样一个IPC的函数调用就完成了。
			 * 当跨进程时,仅以下代码是各自所必须的,去掉了无关代码:
			 *
			 * 其实AIDL的作用就是对Binder的二个方法:Binder.transact()和Binder.onTransact
			 * ()进行封装,
			 * 以供Client端和Server端进行使用。因为实现transact()和onTransact()方法的方式基本上是相同的
			 * ,所以就可以用模板来生成具体的代码
			 * 。理论上讲只需要为Client端生成transact()相关代码,为服务端生成onTransact
			 * ()代码即可,但因为工具无法准确的确定某一个应用到底是Client端还是Server端
			 * ,所以它就生成所有的代码,放在一个文件中。这就是你看到的自动生成的文件。
			 * 还需要注意的一点是Client端的Proxy是组合Binder对象
			 * ,调用其transact()方法;而服务端必须继承Binder对象
			 * ,覆写onTransact()方法。为虾米呢?因为Client是主动发起IPC函数Call
			 * ,所以它可以直接调用Binder的方法来进行IPC。而Server是被动的,是要接收进来的IPC
			 * call,但Service自己无法得知啥时候Call会来
			 * ,因此必须实现回调(onTransact())给Binder,以让Binder在有IPC Call进来的时候告诉Service。
			 * 原理和内幕 AIDL的角色是实现Android平台上面的RPC(Remote Procedure
			 * Call)也即远程例程调用。RPC是IPC中的一种,但是它是以调用在本地或者另一个进程,甚至是另一个主机上的方法的机制。
			 * RPC的目的就是可以让程序不用担心方法具体是在哪个进程里面或者哪以机器上面
			 * ,就像正常的本地方法那样去调用即可,RPC机制会处理所有的具体细节。RPC一般用IDL(Interface Definition
			 * Language)来描述,实现则要看具体的平台和语言。可以参考Wikipedia来看RPC 和IDL 的更多信息。
			 * AIDL提供Android平台的RPC的支持:开发者仅需要要定义AIDL,做一些相关的适配工作,然后就可以使用这些方法了,
			 * 不用具体关心接口描述的方法空究竟是在同一个进程中还是在其他的进程中。这些RPC实现的细节由Binder和系统来处理。
			 */
			myRemoteBookInfo = MyRemoteBookInfo.Stub.asInterface(service);
			try {
				// 建立连接:第四步到服务端请求数据,@Override public BookInfo
				// getBookInfo(java.lang.String tagName)
				// 调用了这个方法去请求数据:mRemote.transact(Stub.TRANSACTION_getBookInfo,
				// _data, _reply, 0);
				BookInfo bookInfo = myRemoteBookInfo.getBookInfo("我是一个tagName");
				textView2.setText(bookInfo.toString());
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {

		}

	}

}

服务端代码:

package com.edify.bluenfcserver.myservice;

import java.util.Date;

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

public class MyRemoteService extends Service {
	//建立连接:第二步,返回一个该提供给客户端操作服务端的对象
	@Override
	public IBinder onBind(Intent intent) {
		return stub;
	}

	/**
	 * 实例化一个对象,该对象就是提供给客户端的对象
	 */
	private MyRemoteBookInfo.Stub stub = new MyRemoteBookInfo.Stub() {
		/**
		 *实现接口未实现的方法
		 */
		//客户端请求是通过这个方法来判断具体请求那个操作@Override public boolean onTransact(int code, android.os.Parcel data, an
		//建立连接:第五步;通过调用该方法回去服务器端的数据信息,操作
		@Override
		public BookInfo getBookInfo(String tagName) throws RemoteException {

			return getBookInfoByTagName(tagName);
		}
	};

	/**
	 * @Description 服务的自身的方法
	 * @Author monkey
	 * @param tagName
	 * @return
	 * @Return BookInfo
	 */
	public BookInfo getBookInfoByTagName(String tagName){
		Log.i("getBookInfoByTagName--------------", tagName);
		if(tagName != null){
			return new BookInfo(1, "尽忠报国", "金庸", 100f, new Date());
		}else{
			return new BookInfo(1, "水浒传", "未知", 200f, new Date());
		}
	}
}
时间: 2024-10-15 13:47:06

android的aidl机制案例的相关文章

Android——Binder(AIDL)机制

1.Binder 1)IBinder和Binder? IBinder是远程对象的基本接口,是为了高性能而设计的轻量级远程调用机制的核心部分.但他不仅用于远程调用,也用于进程内调用.该接口定义了与远程对象间交互的协议.但不要直接实现这个接口,而是继承(extends)Binder. IBinder主要的API是transact(),与之对应的API是Binder.onTransact().通过前者,你能向远程IBinder对象发送发出调用,后者使你的远程对象能够响应接收到的调用.IBinder的A

Android进程间通信(IPC)的AIDL机制:Hello World示例

Android实现IPC可使用Android本身提供的AIDL机制.网上也有很多相关文章,但写的过于繁琐和麻烦,重点也不突出.本文抽丝剥茧从工程角度给出一个最简单的Android AIDL例程关键代码,以最简单的形式说明如何在代码中使用Android AIDL. AIDL首先在逻辑上可分为"服务端"和"客户端".在本示例中,则以两个完全不同.互相独立的Eclipse 项目代表. (1)server.一个Android App,即AIDL的服务端服务提供者. (2)c

Android之——AIDL深入

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47071927 在上一篇博文<Android之--AIDL小结>中,我们简单介绍了一下Android AIDL的用法,而在这篇博文中,我们将深入讲解Android AIDL的用法,同样,在这里我们也通过一个小例子来学习Android 中 AIDL的用法. 好处:多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作, 本文包括: 1 .创建

转 理解Android系统Binder机制

一.Binder机制概述 在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket.pipe等,Android中进程间通信的方式主要有三种: 1.标准Linux Kernel IPC 接口: 2.标准D-BUS接口: 3.Binder接口. 其中,Binder机制是使用最且最被认可的,因为Binder机制有以下优点: 1.相对于其它IPC机制,Binder机制更加简洁和快速: 2.消耗的内存相对更少: 3.传统的IPC机制可能会增加

Android的Handler机制

Handler机制的原理 Android 的 Handler 机制(也有人叫消息机制)目的是为了跨线程通信,也就是多线程通信.之所以需 要跨线程通信是因为在 Android 中主线程通常只负责 UI 的创建和修改,子线程负责网络访问和耗时操作, 因此,主线程和子线程需要经常配合使用才能完成整个 Android 功能. Handler 机制可以近似用图 1 展示.MainThread 代表主线程,newThread 代表子线程. MainThread 是 Android 系统创建并维护的,创建的时

Android Handler消息机制深入浅出

作为Android开发人员,Handler这个类应该是再熟悉不过了,因为几乎任何App的开发,都会使用到Handler这个类,有些同学可能就要说了,我完全可以使用AsyncTask代替它,这个确实是可以的,但是其实AsyncTask也是通过Handler实现的,具体的大家可以去看看源码就行了,Handler的主要功能就是实现子线程和主线程的通信,例如在子线程中执行一些耗时操作,操作完成之后通知主线程跟新UI(因为Android是不允许在子线程中跟新UI的). 下面就使用一个简单的例子开始这篇文章

Android 开发艺术探索——第十章 Android的消息机制

Android 开发艺术探索--第十章 Android的消息机制读书笔记 Handler并不是专门用于更新UI的,只是常被用来更新UI 概述 Android的消息机制主要值得就是Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑. MessageQueue即为消息队列,顾名思义,它的内部存储了一组消息,以队列的的形式对外提供插入和删除的工作.虽然叫队列,但内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表. Looper意思为循

Android Service AIDL 远程调用服务 简单音乐播放实例的实现

Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成. AIDL 是什么 AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码.如果在一个进程中(例如Activi

Android中AIDL实现进程通信(附源码下载)

AIDL概述 之前的博客<Android中通过Messenger与Service实现进程间双向通信>演示了如何通过Messenger实现与Service进行跨进程通信,即IPC.但用Messenger实现的IPC存在一点不足:Service内部维护着一个Messenger,Messenger内部又维护着一个Hanlder,当多个client向该Service发送Message时,这些Message需要依次进入Hanlder的消息队列中,Hanlder只能处理完一个Message之后,再从消息队