Android AIDL 传递对象(Parceable)
来源:互联网 发布:免费开单软件 编辑:程序博客网 时间:2024/05/18 02:03
AndroidStudio 引用 aidl 文件的两种方法
Android AIDL 教程 (一)—— 简单的示例
Android AIDL 传递对象(Parceable)
在上一篇文章中 Android AIDL 教程 (一)—— 简单的示例,我们介绍了怎样使用 AIDL 进行进程间的通讯,并简单写了一个 Demo,今天,让我们一起来学习怎样在 AIDL 中传递对象。
回顾,在上一篇博客中,我们讲到 AIDL 支持以下类型。
- Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)
- String
- CharSequence
- List
List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。 - Map
Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map,如 Map
Server (服务端的实现)
在上一篇博客已经说到,服务端主要有三个步骤
- 将请求抽象成接口,并编写 aidl 文件;
- 编写一个 Service,实现接口,处理客户端的请求,并将 binder 返回回去;
- 在 AndroidManifet 配置 Service,将我们的 Service 暴露出去。
将请求抽象成接口,并编写 aidl 文件
首先我们先来看一下 IPlayService aidl 文件,下面的代码中,我们定义了一个 play 方法,有两个参数,name 是代表歌曲的名字,IPlayListener 是一个接口。需要注意的是它不是一个 java 类,是 aid 文件l 。这样才能在服务端和客户端之间传递
package xj.musicserver;// Declare any non-default types here with import statementsimport xj.musicserver.IPlayListener;interface IPlayService { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void play(String name,IPlayListener iPlayListener);}
package xj.musicserver;// Declare any non-default types here with import statementsimport xj.musicserver.MusicInfo;interface IPlayListener { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void onError(int code); void onSuccess(int code,in MusicInfo musicInfo); }
接下来我们再来看一下我们的实体类 MusicInfo,实现了 Parceable 接口
//下面是自定义的一个MusicInfo子类,实现了Parcelablepublic class MusicInfo implements Parcelable { private long id; private String title; private String album; private int duration; private long size; private String artist; private String url; private String displayName; public MusicInfo(long id, String title, String album, int duration, long size, String artist, String url, String displayName) { this.id = id; this.title = title; this.album = album; this.duration = duration; this.size = size; this.artist = artist; this.url = url; this.displayName = displayName; } public MusicInfo(){ } protected MusicInfo(Parcel in) { id = in.readLong(); title = in.readString(); album = in.readString(); duration = in.readInt(); size = in.readLong(); artist = in.readString(); url = in.readString(); displayName = in.readString(); } //必须提供一个名为CREATOR的static final属性 该属性需要实现android.os.Parcelable.Creator<T>接口 public static final Creator<MusicInfo> CREATOR = new Creator<MusicInfo>() { @Override public MusicInfo createFromParcel(Parcel in) { return new MusicInfo(in); } @Override public MusicInfo[] newArray(int size) { return new MusicInfo[size]; } }; public MusicInfo(long id, String title) { this.id=id; this.title=title; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(title); dest.writeString(album); dest.writeInt(duration); dest.writeLong(size); dest.writeString(artist); dest.writeString(url); dest.writeString(displayName); } public void readFromParcel(Parcel reply) { id=reply.readLong(); title=reply.readString(); album=reply.readString(); duration=reply.readInt(); size=reply.readLong(); artist=reply.readString(); url=reply.readString(); displayName=reply.readString(); }}
接下来看 writeToParcel 和 readFromParcel 方法,需要注意的是 writeToParcel 和 readFromParcel 方法读写的顺序是一一对应的。
这里有一点要提醒大家的是 AndroidStudio 中,我们通过插件会自动帮我们生成 writeToParcel 方法及 CREATOR,通常 readFromParcel 方法是不会自动生成的,需要我们自己手动编写,不然会编译不过。
@Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(title); dest.writeString(album); dest.writeInt(duration); dest.writeLong(size); dest.writeString(artist); dest.writeString(url); dest.writeString(displayName); } public void readFromParcel(Parcel reply) { id=reply.readLong(); title=reply.readString(); album=reply.readString(); duration=reply.readInt(); size=reply.readLong(); artist=reply.readString(); url=reply.readString(); displayName=reply.readString(); }
注意了,接下来我们需要写一个 MusicInfo.aidl 文件
package xj.musicserver;// Declare any non-default types here with import statementsparcelable MusicInfo;
指定包名,并声明 MusicInfo 是 parcelable,注意 parcelable 是小写的 p,不是大写的 P。这是一个规范,google 官方指定需要的。同时 MusicInfo.aidl 和 MusicInfo.java 需要放置在同个包中。
关于怎样在 AndroidStudio 中配置 aidl 的可以参考我的这一篇博客。AndroidStudio 引用 aidl 文件的两种方法
第二步编写一个 Service,实现接口,处理客户端的请求,并将 binder 返回回去;
IPlayService.Stub mIPlayService=new IPlayService.Stub() { @Override public void play(String name, final IPlayListener iPlayListener) throws RemoteException { MusicTask musicTask = new MusicTask(getApplicationContext(), name, ""); musicTask.setIResultListener(new MusicTask.IResultListener() { @Override public void onSuccess(MusicInfo musicInfo) { try { iPlayListener.onSuccess(0,musicInfo); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onFail(int code, MusicInfo musicInfo) { try { iPlayListener.onError(0); } catch (RemoteException e) { e.printStackTrace(); } } }); musicTask.execute(); }};@Nullable@Overridepublic IBinder onBind(Intent intent) { LogUtil.i(TAG, "onBind: intent = " +intent.toString()); return mIPlayService;}
这里我们所做的工作就是到数据库里面查询看是否有相应的歌曲,如果有,通过 aidl 回调,告诉客户端我们查找成功,调用 onSuccess 方法,没有找到,调用客户端的 onError 方法。
package xj.musicserver;import android.content.ContentResolver;import android.content.Context;import android.database.Cursor;import android.net.Uri;import android.os.AsyncTask;import android.provider.MediaStore;import android.support.annotation.NonNull;import android.text.TextUtils;import android.util.Log;import java.util.ArrayList;/** * @author meitu.xujun on 2017/10/17 * @version 0.1 */public class MusicTask extends AsyncTask<Void,Void,Integer> { // 这里只贴出主要代码,详细代码可到文章的末尾下载。 public MusicTask(Context context, String name, String artist){ mContext = context.getApplicationContext(); mName = name; mArtist = artist; } @Override protected Integer doInBackground(Void... params) { LogUtil.i(TAG,"doInBackground: mName="+mName +" mArtist"+mArtist); mResult = ""; ContentResolver contentResolver = mContext.getContentResolver(); Cursor cursor; if (TextUtils.isEmpty(mArtist)) { cursor = contentResolver.query(contentUri, projection, where_title, new String[]{getFixName(mName)},null); }else{ cursor=contentResolver.query(contentUri, projection, where_title_and_artist, new String[]{getFixName(mName),getFixName(mArtist)},null); if(cursor==null || cursor.getCount()<=0){ cursor = contentResolver.query(contentUri, projection, where_title, new String[]{getFixName(mName)},null); } } if(cursor==null || cursor.getCount()<=0){ return RESULT_FAIL_MUSIC_NULL; } int displayNameCol = cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME); int albumCol = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM); int idCol = cursor.getColumnIndex(MediaStore.Audio.Media._ID); int durationCol = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION); int sizeCol = cursor.getColumnIndex(MediaStore.Audio.Media.SIZE); int artistCol = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST); int urlCol = cursor.getColumnIndex(MediaStore.Audio.Media.DATA); int titleCol = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE); mMusicInfos = new ArrayList<>(); String songName=""; while (cursor.moveToNext()){ songName = cursor.getString(titleCol); MusicInfo musicInfo = getMusicInfo(cursor, displayNameCol, albumCol, idCol, durationCol, sizeCol, artistCol, urlCol,titleCol); mMusicInfos.add(musicInfo); if(songName.equals(mName)){ mResult =mName; mMusicInfo=musicInfo; break; } } if(mMusicInfo==null){ mMusicInfo =mMusicInfos.get(0); } return RESULT_SUCUESS; } @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); Log.i(TAG, "onPostExecute: result =" +result); if(mIResultListener==null){ return; } if(result==RESULT_SUCUESS){ mIResultListener.onSuccess(mMusicInfo); }else{ mIResultListener.onFail(result,mMusicInfo); } } ----- public void setIResultListener(IResultListener IResultListener) { mIResultListener = IResultListener; } public interface IResultListener{ void onSuccess(MusicInfo musicInfo); void onFail(int code, MusicInfo musicInfo); }}
在 AndroidManifet 配置 Service,将我们的 Service 暴露出去。
<service android:name=".PlayService" android:exported="true" android:process=":remote"> <intent-filter> <action android:name="xj.musicserver.IPlayService"/> </intent-filter></service>
到这里我们服务端的配置就完成了
Client(客户端) 的实现
在上一篇博客的时候,我们有讲到实现客户端大概需要几个步骤:
- 将服务端的 aidl 文件 copy 过来,注意要放在同一个包下。
- 通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例。
- 之后如果想与服务端通讯,通过保存下来的 Binder,即可调用服务端的方法。
第一步:将服务端的 aidl 文件 copy 过来,注意要放在同一个包下。
如下图所示,我们将 IPlayListener.aidl,IPalyService.aidl,MusicInfo.aidl 和 MuicInfo.java copy 到客户端
第二步:通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例。
这里的 Action 是与服务端一一对应的。
case R.id.btn_start_service: LogUtil.i(TAG,"onButtonClick: btn_start_service="); Intent intent = new Intent(ACTION); intent.setPackage(XJ_MUSICSERVER); bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE); public static final String ACTION = "xj.musicserver.IPlayService"; public static final String XJ_MUSICSERVER = "xj.musicserver";
第三步:通过第二步保存下来 的 mIBinder,与服务端进行通讯。
当我们调用 mIPlayService.play 方法的时候,服务端会去查找本地是否存在 丑八怪 这首歌,查找到的时候会回调 onSuccess 方法,查找不到的时候会回调 onError 方法。
case R.id.btn_contact: LogUtil.i(TAG,"onButtonClick: btn_contact="); if(mIPlayService!=null){ mIPlayService.play("丑八怪", mPlayListener); }IPlayListener.Stub mPlayListener=new IPlayListener.Stub(){ @Override public void onError(int code) throws RemoteException { LogUtil.i(TAG,"onError: code = "+code); } @Override public void onSuccess(int code, MusicInfo musicInfo) throws RemoteException { LogUtil.i(TAG,"onSuccess: code = "+code+ " musicInfo" + musicInfo.toString()); }};
到此这篇博客为止。
DEMO 下载地址
最后的最后,卖一下广告,欢迎大家关注我的微信公众号,扫一扫下方二维码或搜索微信号 stormjun,即可关注。 目前专注于 Android 开发,主要分享 Android开发相关知识和一些相关的优秀文章,包括个人总结,职场经验等。
- Android AIDL 传递对象(Parceable)
- Android之AIDL示例(传递对象)
- Android Parceable传递复杂类型数据
- Android使用AIDL传递对象
- Android AIDL传递对象问题
- Android Parceable的简单用法,如何传递List<T>和对象,中间写入数组
- intent传递对象,实现parceable或者serializable,及回传值
- Android--Service之AIDL传递复杂对象
- Android Service AIDL的学习,传递对象
- 学习笔记-Android AIDL传递对象数据
- 关于AIDL传递复杂数据(对象)
- aidl 传递对象
- Aidl实现对象传递
- android之Parceable
- android intent parceable
- Android笔记三:Android 接口定义语言 (AIDL)--传递对象
- android之Service介绍之三 AIDL与传递对象
- android之Service介绍之三 AIDL与传递对象
- java web项目:学生考试系统(从入门到跑路)onlinexamnew:(1)环境搭配
- 编写函数: unsigned int reverse_bit(unsigned int value); 这个函数的返回值value的二进制位模式从左到右翻转后的值。
- git使用总结
- Linux下yum命令详解
- 数字与英文单词的转换
- Android AIDL 传递对象(Parceable)
- 【Unity】FOV战争迷雾
- Maven之(六)setting.xml配置文件详解
- ios10中禁止Safari浏览器用户缩放页面
- xdoj ranting记
- algorithm test
- 讲给Android程序员看的前端教程(20)——float浮动
- 关于C和我
- Codeforces Round #444 (Div. 2)