在上一篇中介绍了Andorid中的进程间的通信方式AIDL,本篇文章将介绍传递复杂数据的AIDL Service

下面通过一个示例说明:

本例子中用到了两个自定义类型:Person与Pet, 其中Person对象作为调用远程Service的参数,而Pet将作为返回值。就像RMI要求远程调用的参数和返回值必须实现Serializable接口,Android要求调用远程Service的参数和返回值都必须实现Parcelable接口。

实现Parcelable接口不仅要求实现该接口里定义的方法,还有两个要求:

1、要求在实现类中定义一个名为CREATOR、类型为Rarcelable.Creator的静态Field

2、要求使用AIDL代码来定义这些自定义类型。

实现Parcelable接口相当于Android提供的一种自定义序列化机制。Java序列化机制要求序列化类必须实现Serializable接口,而Android的序列化机制则要求自定义类必须实现Parcelable接口。

下面我们先来使用AIDL代码定义我们的自定义类型Person和Pet

Person.aidl

parcelable Person;

Pet.aidl

parcelable Pet; 

可以看到,使用AIDL定义自定义类型只要一行代码

接下来我们来定义实现Parcelable接口的Persion类和Pet类

Person.java

import android.os.Parcel;
import android.os.Parcelable; /**
*
* @author 大碗干拌
* @url http://blog.csdn.net/dawanganban
*/
public class Person implements Parcelable
{
private Integer id;
private String name;
private String pass; public Person()
{
}
public Person(Integer id, String name, String pass)
{
super();
this.id = id;
this.name = name;
this.pass = pass;
}
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getPass()
{
return pass;
}
public void setPass(String pass)
{
this.pass = pass;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((pass == null) ? 0 : pass.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
if (pass == null)
{
if (other.pass != null)
return false;
}
else if (!pass.equals(other.pass))
return false;
return true;
}
// 实现Parcelable接口必须实现的方法
@Override
public int describeContents()
{
return 0;
}
// 实现Parcelable接口必须实现的方法
@Override
public void writeToParcel(Parcel dest, int flags)
{
//把该对象所包含的数据写到Parcel
dest.writeInt(id);
dest.writeString(name);
dest.writeString(pass);
} // 添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口
public static final Parcelable.Creator<Person> CREATOR
= new Parcelable.Creator<Person>() //①
{
@Override
public Person createFromParcel(Parcel source)
{
// 从Parcel中读取数据,返回Person对象
return new Person(source.readInt()
, source.readString()
, source.readString());
} @Override
public Person[] newArray(int size)
{
return new Person[size];
}
};
}

Pet.java

import android.os.Parcel;
import android.os.Parcelable; /**
*
* @author 大碗干拌
* @url http://blog.csdn.net/dawanganban
*/
public class Pet implements Parcelable
{
private String name;
private double weight;
public Pet()
{
}
public Pet(String name, double weight)
{
super();
this.name = name;
this.weight = weight;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public double getWeight()
{
return weight;
}
public void setWeight(double weight)
{
this.weight = weight;
} @Override
public int describeContents()
{
return 0;
}
/* (non-Javadoc)
* @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
*/
@Override
public void writeToParcel(Parcel dest, int flags)
{
//把该对象所包含的数据写到Parcel
dest.writeString(name);
dest.writeDouble(weight);
} // 添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口
public static final Parcelable.Creator<Pet> CREATOR
= new Parcelable.Creator<Pet>()
{
@Override
public Pet createFromParcel(Parcel source)
{
// 从Parcel中读取数据,返回Person对象
return new Pet(source.readString()
, source.readDouble());
} @Override
public Pet[] newArray(int size)
{
return new Pet[size];
}
};
@Override
public String toString()
{
return "Pet [name=" + name + ", weight=" + weight + "]";
}
}

上面代码定义了一个实现Parcelable接口的类,实现该接口主要就是要实现writeToParcel(Parel dest, int flags)方法,该方法负责把Person对象的数据写入Parcel中。与此同时,该类必须定义一个类型为Parcelable.Createor<Person>、名为CREATEOR的静态常亮,该静态常亮的值负责恢复从Parcel数据包中恢复Person对象,因此该对象定义的creaeFromPerson()方法用于恢复Person对象。

实际上Person类实现Parcelable接口也是一种序列化机制,只是Android没有直接使用Java提供的序列化机制,而是提供了Parcelable这种轻量级的序列化机制。

有了Person、Pet类后接下来就可以使用AIDL来定义通信接口了,定义通信接口的代码如下:

interface IPet
{
// 定义一个Person对象作为传入参数
List<Pet> getPets(in Person owner);
}

上面的in代表的是传入参数的方式是传参数

接下来开发一个Service类,让Service类的onBind方法返回IPet实现类的实例。代码如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.crazyit.service.IPet.Stub; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException; /**
*
* @author 大碗干拌
* @url http://blog.csdn.net/dawanganban
*/
public class ComplexService extends Service
{
private PetBinder petBinder;
private static Map<Person , List<Pet>> pets
= new HashMap<Person , List<Pet>>();
static
{
// 初始化pets Map集合
ArrayList<Pet> list1 = new ArrayList<Pet>();
list1.add(new Pet("旺财" , 4.3));
list1.add(new Pet("来福" , 5.1));
pets.put(new Person(1, "sun" , "sun") , list1);
ArrayList<Pet> list2 = new ArrayList<Pet>();
list2.add(new Pet("kitty" , 2.3));
list2.add(new Pet("garfield" , 3.1));
pets.put(new Person(2, "bai" , "bai") , list2);
}
// 继承Stub,也就是实现额IPet接口,并实现了IBinder接口
public class PetBinder extends Stub
{
@Override
public List<Pet> getPets(Person owner) throws RemoteException
{
// 返回Service内部的数据
return pets.get(owner);
}
}
@Override
public void onCreate()
{
super.onCreate();
petBinder = new PetBinder();
}
@Override
public IBinder onBind(Intent arg0)
{
/* 返回catBinder对象
* 在绑定本地Service的情况下,该catBinder对象会直接
* 传给客户端的ServiceConnection对象
* 的onServiceConnected方法的第二个参数;
* 在绑定远程Service的情况下,只将catBinder对象的代理
* 传给客户端的ServiceConnection对象
* 的onServiceConnected方法的第二个参数;
*/
return petBinder; //①
}
@Override
public void onDestroy()
{
}
}

在AnroidMainfest.xml文件中配置Service,和前面的配置方法相同

下面我们来开发客户端

开发客户端的第一步不仅需要把IPet.aidl文件复制过去,还需要把定义Person类的Java文件,AIDL文件,定义Pet类的Java文件、AIDL文件也复制过去。

客户端代码如下:

import java.util.List;

import org.crazyit.service.IPet;
import org.crazyit.service.Person;
import org.crazyit.service.Pet; import android.app.Activity;
import android.app.Service;
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.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView; /**
*
* @author 大碗干拌
* @url http://blog.csdn.net/dawanganban
*
*/
public class ComplexClient extends Activity
{
private IPet petService;
private Button get;
EditText personView;
ListView showView;
private ServiceConnection conn = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name
, IBinder service)
{
// 获取远程Service的onBind方法返回的对象的代理
petService = IPet.Stub.asInterface(service);
} @Override
public void onServiceDisconnected(ComponentName name)
{
petService = null;
}
}; @Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
personView = (EditText) findViewById(R.id.person);
showView = (ListView) findViewById(R.id.show);
get = (Button) findViewById(R.id.get);
// 创建所需绑定的Service的Intent
Intent intent = new Intent();
intent.setAction("org.crazyit.aidl.action.COMPLEX_SERVICE");
// 绑定远程Service
bindService(intent, conn, Service.BIND_AUTO_CREATE);
get.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
try
{
String personName = personView.getText().toString();
// 调用远程Service的方法
List<Pet> pets = petService.getPets(new Person(1,
personName, personName)); //①
// 将程序返回的List包装成ArrayAdapter
ArrayAdapter<Pet> adapter = new ArrayAdapter<Pet>(
ComplexClient.this,
android.R.layout.simple_list_item_1, pets);
showView.setAdapter(adapter);
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
});
} @Override
public void onDestroy()
{
super.onDestroy();
// 解除绑定
this.unbindService(conn);
}
}

Android菜鸟的成长笔记(22)——Android进程间传递复杂数据(AIDL)的更多相关文章

  1. Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)

    原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...

  2. Android菜鸟的成长笔记(7)——什么是Activity

    原文:[置顶] Android菜鸟的成长笔记(7)——什么是Activity 前面我们做了一个小例子,在分析代码的时候我们提到了Activity,那么什么是Activity呢? Activity是An ...

  3. Android菜鸟的成长笔记(4)——你真的理解了吗?

    原文:Android菜鸟的成长笔记(4)--你真的理解了吗? 在上一篇中我们查看了QQ的apk源文件中的布局结构,并仿照QQ完成了我们第一个应用的界面,详细请看<Android菜鸟的成长笔记&g ...

  4. Android菜鸟的成长笔记(17)—— 再看Android中的Unbounded Service

    原文:Android菜鸟的成长笔记(17)-- 再看Android中的Unbounded Service 前面已经写过关于startService(Unbounded Service)的一篇文章:&l ...

  5. Android菜鸟的成长笔记(3)——给QQ登录界面说So Easy

    原文:Android菜鸟的成长笔记(3)--给QQ登录界面说So Easy 上一篇:Android菜鸟的成长笔记(2)--第一个Android应用 我们前面已经做了第一个Android应用程序,虽然有 ...

  6. Android菜鸟的成长笔记(2)——第一个Android应用

    原文:Android菜鸟的成长笔记(2)--第一个Android应用 上一篇:Android菜鸟的成长笔记(1)--Anddroid环境搭建从入门到精通 在上一篇Android菜鸟的成长笔记(1)中我 ...

  7. Android菜鸟的成长笔记(1)——Android开发环境搭建从入门到精通

    原文:Android菜鸟的成长笔记(1)--Android开发环境搭建从入门到精通 今天在博客中看到好多Android的初学者对Android的开发环境的搭建不熟悉而导致不能进行学习,所以我决定自己写 ...

  8. Android菜鸟的成长笔记(13)——异步任务(Async Task)

    原文:[置顶] Android菜鸟的成长笔记(13)——异步任务(Async Task) Android的UI线程主要负责处理用户的事件及图形显示,因此主线程UI不能阻塞,否则会弹出一个ANR(App ...

  9. Android菜鸟的成长笔记(12)——Handler、Loop、MessageQueue

    原文:[置顶] Android菜鸟的成长笔记(12)——Handler.Loop.MessageQueue 当一个程序第一次启动时,Android会启动一条主线程(Main Thread),主线程主要 ...

  10. Android菜鸟的成长笔记(11)——Android中的事件处理

    原文:[置顶] Android菜鸟的成长笔记(11)——Android中的事件处理 Android提供了两种方式来处理事件,一个是基于回调的事件处理,另一个是基于监听的事件处理,举个例子: 基于回调的 ...

随机推荐

  1. 分治法(divide & conquer)与动态规划(dynamic programming)应用举例

    动态规划三大重要概念:最优子结构,边界,状态转移公式(问题规模降低,如问题由 n 的规模降低为 n−1 或 n−2 及二者之间的关系): 0. 爬台阶 F(n)⇒F(n−1)+F(n−2) F(n−1 ...

  2. UWP 新手教程1——UWP的前世今生

    文件夹 引言 设备族群 UI 和通用输入模式 通用控件和布局面板 工具 自适应扩展 通用输入处理 引言 在本篇文章中,可以掌握下面知识: 设备族群,怎样决定目标设备 新的UI控件和新面板帮助你适应不同 ...

  3. (转)Nginx在RedHat中系统服务配置脚本

    转自:http://binyan17.iteye.com/blog/1688308 以下代码是在前人的基础上,结合自己服务器实际情况修改的,本人服务器环境是:CentOS 6.31.创建启动脚本,  ...

  4. 将OpenCV捕获的摄像头加载到picture控件中

    CRect rect; CStatic* pStc; CDC* pDC; HDC hDC; pStc = (CStatic*)GetDlgItem(IDC_CAM);//IDC_CAM是Picture ...

  5. Android屏幕信息获取

    Android中有时需要获取屏幕的size信息以便对控件位置进行动态控制,最近做了一些研究,现在将获取屏幕大小信息的方法总结如下,可能存在一些地方理解的不全面. 1.getMetrics Displa ...

  6. UE4制作插件的插件神器pluginCreator

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/45644007 作者:car ...

  7. php实现不用加减乘除号做加法(1、善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍)

    php实现不用加减乘除号做加法(1.善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍) 一.总结 1.善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍 二.ph ...

  8. valgrind,arm-linux交叉编译

    1. 下载及解压valgrind-3.9.0 2.CC=/opt/hisi-linux/x86-arm/arm-hisiv200-linux/target/bin/arm-hisiv200-linux ...

  9. Linux基本命令(一)

    目标 熟练使用 Linux常用的命令 ls clear cd pwd mkdir touch rm cp mv tree chmod find grep 重定向 软连接.硬链接 压缩 shutdown ...

  10. ijkplayer阅读笔记02-创建音视频读取,解码,播放线程

    本节主要介绍音视频读取和解码线程的创建及启动,代码流程例如以下: IjkMediaPlayer_prepareAsync{ ijkmp_prepare_async_l{ ijkmp_change_st ...