android aidl参数contentvalues,AIDL 传递对象(Parceable)、传递接口

通常,AIDL 支持以下类型。

Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)

String

CharSequence

List

List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。

Map

Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map,如 Map

注意事项

在 aidl 文件中,除了 Java 编程语言中的所有原语类型、String、CharSequence、List、Map,其他在 AIDL 文件中用到的类,你必须使用 import 语句导入,否则会报错。

当你使用实现Parceable 的自定义类型的时候,当其作为参数的时候,你必须为其制定是输入或者是输出参数。

in 表示输入参数,即服务端可以修改该类型

out 表示输出参数,即客户端可以修改该类型,客户端不行

inout 表示客户端和服务端都可以修改该类型

如: void onSuccess(int code,in MusicInfo musicInfo);

Server (服务端的实现)

服务端主要有三个步骤

将请求抽象成接口,并编写 aidl 文件;

编写一个 Service,实现接口,处理客户端的请求,并将 binder 返回回去;

在 AndroidManifet 配置 Service,将我们的 Service 暴露出去。

一、将请求抽象成接口,并编写 aidl 文件

首先我们先来看一下 IPlayService aidl 文件,下面的代码中,我们定义了一个 play 方法,有两个参数,name 是代表歌曲的名字,IPlayListener 是一个接口。需要注意的是它不是一个 java 类,是 aidl 文件 。这样才能在服务端和客户端之间传递

package xj.musicserver;

// Declare any non-default types here with import statements

import 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);

}

要手动添加 import xj.musicserver.IPlayListener;

package xj.musicserver;

// Declare any non-default types here with import statements

import 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);

}

要手动添加 import xj.musicserver.MusicInfo;

接下来我们再来看一下我们的实体类 MusicInfo,实现了 Parceable 接口

//下面是自定义的一个MusicInfo子类,实现了Parcelable

public 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接口

public static final Creator CREATOR = new Creator() {

@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 方法是不会自动生成的,需要我们自己手动编写,不然会编译不过。

注意了,接下来我们需要写一个 MusicInfo.aidl 文件

package xj.musicserver;

// Declare any non-default types here with import statements

parcelable MusicInfo;

指定包名,并声明 MusicInfo 是 parcelable,注意 parcelable 是小写的 p,不是大写的 P。这是一个规范,google 官方指定需要的。同时 MusicInfo.aidl 和 MusicInfo.java 需要放置在同个包中。

becb23bd1507

image.png

二、第二步,编写一个 Service,实现接口,处理客户端的请求,并将 binder 返回回去;

(以下代码涉及到两个接口的传递,过程大致如此,即自定义动作IPlayListener接口从客户端传递到服务端,服务端再将动作传递到任务类MusicTask.IResultListener接口中。)

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

@Override

public 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 {

// 这里只贴出主要代码,详细代码可到文章的末尾下载。

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 暴露出去。

android:name=".PlayService"

android:exported="true"

android:process=":remote">

到这里我们服务端的配置就完成了

Client(客户端) 的实现

实现客户端大概需要几个步骤:

将服务端的 aidl 文件 copy 过来,注意要放在同一个包下。

通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例。

之后如果想与服务端通讯,通过保存下来的 Binder,即可调用服务端的方法。

一、第一步:将服务端的 aidl 文件 copy 过来,注意要放在同一个包下。

如下图所示,我们将 IPlayListener.aidl,IPalyService.aidl,MusicInfo.aidl 和 MuicInfo.java copy 到客户端

becb23bd1507

image.png

二、第二步:通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例。

(注意在 Android 5.0以后,不能通过隐式 Intent 启动 service,必须制定包名)

这里的 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());

}

};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值