黑夜

黑夜给了我黑色的眼睛,我却用它寻找光明~

传值方式

AIDL是同意跨进程传递值的,一般来说有三种方式:

- 广播;这样的算是比較常见的一种方式了,传递小数据不错

- 文件;这个是保存到文件里。然后读取,传递大数据不错

- Service Bind模式。这个算是居中的一种方式,只是效率要高的多,唯一麻烦的是编写代码较为麻烦。

特别是复杂类型数据传递麻烦。

其是,另一些其它的办法进行数据传递。另外传递也并非仅仅能够使用一种,能够採用几种结合的方式进行。

今天要说的就是Service Bind进行复杂数据的传递。


传递类型

在AIDL中之所以使用Bind进行传递会比較麻烦是由于:其在跨进程的情况下仅仅同意传递例如以下类型数据:

- String

- CharSequence

- android.os.Parcelable

- java.util.List

- java.util.Map

尽管能够使用 List与Map可是其类型一样不能使用复杂类型;当然上面 int、long、bool就没有单独写出来了。

如过要进行复杂数据传递,如传递User类的实例,此时就要使用Parcelable来辅助完毕。

简单流程

Created with Raphaël 2.1.0A进程数据User在A进程把User打包为Parcelable在B进程把Parcelable解包为UserB进程数据User

其调用方式依旧为:绑定服务->得到目标服务的Binder->调用相应方法

跨进程传递数据麻烦就在于打包/解包Parcelable的操作。

目标:开启一个独立进程的服务,在主进程中绑定目标服务。调用服务的方法。

实现:将须要进行复杂传递的数据类,继承Parcelable,并实现当中的序列化与反序列化方法。

传递类

传递类包括两个:User.java、User.aidl

当中java类是详细的实现,aidl文件仅仅仅仅是用于对java文件的声明。告知进程其能够看作Parcelable处理。

User.Java

package net.qiujuer.sample.service.bean;

import android.os.Parcel;
import android.os.Parcelable; import java.util.UUID; /**
* Created by qiujuer on 15/7/15.
*/
public class User implements Parcelable {
private UUID id;
private int age;
private String name; public User(int age, String name) {
this.age = age;
this.name = name;
this.id = UUID.randomUUID();
} protected User(Parcel in) {
// Id
long m = in.readLong();
long l = in.readLong();
id = new UUID(m, l); age = in.readInt();
name = in.readString();
} public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
} @Override
public User[] newArray(int size) {
return new User[size];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
// ID
long m = id.getMostSignificantBits();
long l = id.getLeastSignificantBits();
dest.writeLong(m);
dest.writeLong(l); dest.writeInt(age);
dest.writeString(name);
} @Override
public String toString() {
return "Id:" + id.toString() + " Age:" + age + " Name:" + name;
}
}

在类中,包括三个属性。两个基本类型,一个UUID,对于基本类型能够直接序列化。而UUID则不能,此时两个方案。一种是把UUID看作String进行处理。当解包时则把String转换为UUID就可以。

另外一种则是得到当中重要的作用,各自是两个long值。然后对long值进行传递,并反序列化。

在类中,我们实现了Parcelable接口,则须要完毕两个方法与一个静态值操作。

- describeContents 为描写叙述方法。通常返回0

- writeToParcel 详细的写入操作,在这里对须要传输的数据进行写入。请一定须要注意的是写入顺序则决定了读取顺序

- CREATOR 此静态属性,则是为了反编译时使用,在Parcelable进行反编译时将会调用该属性,所以名称写法基本是固定不变的。

- User 在该类的构造函数中。我们对其进行了反序列化读取数据操作。

User.aidl

// User.aidl
package net.qiujuer.sample.service.bean; parcelable User;

在该文件里。仅仅须要两行代码就OK,一个指定包名,一个为parcelable申明。

# Service类

这个部分主要包括两个文件。一个AIDL申明文件

IServiceAidlInterface.aidl

// IServiceAidlInterface.aidl
package net.qiujuer.sample.service;
import net.qiujuer.sample.service.bean.User; // Declare any non-default types here with import statements interface IServiceAidlInterface {
void addAge();
void setName(String name);
User getUser();
}

在该文件里,定义了一个接口。当中有一个方法getUser(),该方法返回服务中的User类的实例;当然须要使用该类所以须要加上import net.qiujuer.sample.service.bean.User;

IndependentService.java

package net.qiujuer.sample.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException; import net.qiujuer.sample.service.bean.User; public class IndependentService extends Service {
private ServiceBinder mBinder; public IndependentService() {
} @Override
public IBinder onBind(Intent intent) {
if (mBinder == null)
mBinder = new ServiceBinder();
return mBinder;
} class ServiceBinder extends IServiceAidlInterface.Stub {
private User user; public ServiceBinder() {
user = new User(21, "XiaoMing");
} @Override
public void addAge() throws RemoteException {
user.setAge(user.getAge() + 1);
} @Override
public void setName(String name) throws RemoteException {
user.setName(name);
} @Override
public User getUser() throws RemoteException {
return user;
}
} }

该类为详细的服务实现,在该服务中实现了服务接口,并进行了简单实现。

文件梳理与配置

文件结构

独立进程配置

由于我们须要让服务为独立进程,所以须要在AndroidManifest文件里Service申明的地方加上process属性:

<?

xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.qiujuer.sample.service"> <application
android:allowBackup="true"
android:label="@string/app_name">
<service
android:name=".IndependentService"
android:enabled="true"
android:exported="true"
android:permission="1000"
android:process=":AidlService" />
</application> </manifest>

在这里我设置的是:android:process=”:AidlService”

使用

在APP Model中。我建立了一个MainActivity,并在当中调用服务的方法。

核心代码

public class MainActivity extends AppCompatActivity {
private final String TAG = this.getClass().getSimpleName();
private TextView mText; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mText = (TextView) findViewById(R.id.txt_str); bindService();
} @Override
protected void onDestroy() {
super.onDestroy();
unBindService();
} private IServiceAidlInterface mService = null; private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mService = IServiceAidlInterface.Stub.asInterface(iBinder);
if (mService != null)
run();
else
showText("Bind Error.");
} @Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
}
}; private void bindService() {
// UnBind
unBindService(); Intent intent = new Intent(this, IndependentService.class);
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
} private void unBindService() {
// Service
IServiceAidlInterface service = mService;
mService = null;
if (service != null) {
unbindService(mConn);
}
} private void run() {
User user = null;
try {
user = mService.getUser();
showText(user.toString()); mService.addAge();
user = mService.getUser();
showText(user.toString()); mService.setName("FangFang");
user = mService.getUser();
showText(user.toString()); } catch (RemoteException e) {
e.printStackTrace();
showText(e.toString());
}
} private void showText(String str) {
Log.d(TAG, str);
mText.append("\n");
mText.append(str);
}
}

打印日志

MainActivity﹕ Id:cdfb5bb4-7674-4a8a-b754-92256dfea8f4 Age:21 Name:XiaoMing

MainActivity﹕ Id:cdfb5bb4-7674-4a8a-b754-92256dfea8f4 Age:22 Name:XiaoMing

MainActivity﹕ Id:cdfb5bb4-7674-4a8a-b754-92256dfea8f4 Age:22 Name:FangFang

进程

能够看出,服务的进程的确是独立于主进程的。

引申

在这里,我们是传递的一个User。假如传递的User中又包括一个Account类呢?Account中又包括其它的类呢?这个该怎样办?

有两种办法:

第一种:使用上面UUID传递相似的方式。得到当中的核心数据,然后传递,在解包时进行还原。

另外一种:将类也实现Parcelable接口。这样就能完美的攻克了。

在这里简单写一下另外一种的代码:

Account.java

public class Account implements Parcelable {
private String name; protected Account(Parcel in) {
name = in.readString();
} public static final Creator<Account> CREATOR = new Creator<Account>() {
@Override
public Account createFromParcel(Parcel in) {
return new Account(in);
} @Override
public Account[] newArray(int size) {
return new Account[size];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
}

User.java

这里仅仅写修改部分。事实上这些修改的东西。全然能够借助编译工具自己主动生成,你仅仅须要写好属性。然后继承接口。然后让编译工具帮助你完毕接口相应方法就OK。

public class User implements Parcelable {
private Account account; protected User(Parcel in) {
...
account = in.readParcelable(Account.class.getClassLoader());
} @Override
public void writeToParcel(Parcel dest, int flags) {
...
dest.writeParcelable(account, flags);
}
}

另外须要注意的是。在aidl中申明类。仅仅仅仅须要申明aidl接口中须要传递的类就OK。在这里直接传递的类仅仅有User。所以仅仅须要写一个User.aidl文件就OK,就算User中包括了Account类,但不须要写Account.aidl文件来申明。

代码

当然,源代码肯定是会有的:

AidlService 源代码

写在最后

近期没事儿捣鼓了一个APP[UPMiss]。一个简单的生日,纪念日提醒软件。欢迎大家尝鲜。

UPMiss} 思念你的夏天

下载地址:

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer

站点:www.qiujuer.net

开源库:github.com/qiujuer/Genius-Android

开源库:github.com/qiujuer/Blink

转载请注明出处:http://blog.csdn.net/qiujuer/article/details/46885987

—— 学之开源,用于开源;刚開始学习的人的心态。与君共勉。

========================================================

Android AIDL Service 跨进程传递复杂数据的更多相关文章

  1. Android AIDL Service

    AIDL Service //跨进程调用Service    一个APK想调用另一个APK中的Service 如何实现AIDL //定义两个进程之间的通信接口 Demo1 传递简单数据 AidlSer ...

  2. Android中的跨进程通信方法实例及特点分析(一):AIDL Service

    转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481 近期有一个需求就是往程序中增加大数据的採集点,可是由于我们的Andro ...

  3. Service官方教程(11)Bound Service示例之2-AIDL 定义跨进程接口并通信

    Android Interface Definition Language (AIDL) 1.In this document Defining an AIDL Interface Create th ...

  4. 不依赖AIDL的跨进程通信

    http://blog.csdn.net/lmj623565791/article/details/38461079 如果知道AIDL和binder的原理,可以简单写一个不依赖AIDL的跨进程通信 不 ...

  5. android 远程Service以及AIDL的跨进程通信

    在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问 ...

  6. Android四大组件应用系列5——使用AIDL实现跨进程调用Service

    一.问题描述 Android应用程序的四大组件中Activity.BroadcastReceiver.ContentProvider.Service都可以进行跨进程.在上一篇我们通过ContentPr ...

  7. Android IPC机制(三)使用AIDL实现跨进程方法调用

    上一篇文章中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户 ...

  8. Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用

    在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法.可是我们能发现Messenger是以串行的方式来处理client ...

  9. Android中的跨进程调用技术AIDL

    什么是AIDL Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信. 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用 ...

随机推荐

  1. HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】

    本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...

  2. 使用 Hibernate 完成 HibernateUtils 类 (适用于单独使用Hibernate或Struts+Hibernate)

    package com.istc.Utilities; import org.hibernate.Session; import org.hibernate.SessionFactory; impor ...

  3. spoj - Longest Common Substring(后缀自动机模板题)

    Longest Common Substring 题意 求两个串的最长公共子串. 分析 第一个串建后缀自动机,第二个串在自动机上跑,对于自动机上的结点(状态)而言,它所代表的最大长度为根结点到当前结点 ...

  4. 学习LSM(Linux security module)之三:Apparmor的前世今生和基本使用

    感冒了,感觉一脑子浆糊,真是蛋疼. 先粗略讲一些前置知识. 一:MAC和DAC DAC(Discretionary Access Control),自主访问控制,是最常用的一类访问控制机制,意思为主体 ...

  5. DeprecationWarning: current URL string parser is deprecated解决方法

    我最近在使用mongoDB的时候,发现了这个警告语句,纳闷了,按照官方文档的教程去连接数据库还能出错,也是醉了. 后来尝试去阅读相关资料,发现只是需要将{ useNewUrlParser: true ...

  6. 网站模糊测试爆破工具Wfuzz

    网站模糊测试爆破工具Wfuzz   模糊测试爆破使用模糊测试的方式对HTTP请求中的各个参数同时进行猜测爆破.例如,渗透测试人员可以采用不同的HTTP请求方式来访问由字典生成的网页路径,以判断网页目录 ...

  7. bit & byte & B & KB & Kbps & KBps & ps

    存储单位bit & byte & B & KB & Kbps & KBps & ps    (bit,位:byte,字节:区别) Bit,位 :二进制数 ...

  8. iOS 取消警告

    第一步找到要取消的警告类型 在相应的警告上右击->Reveal in Log 被选中的-Wdeprecated-declarations就是我们所要的警告类型了. -W是前缀,这个前缀表示的是 ...

  9. 如何垂直居中元素(浮动元素&居中一个<img>)?

    1.如何居中一个浮动元素? 方法一:已知元素的高度   <!DOCTYPE html> <html lang="en"> <head> < ...

  10. canvas如何兼容IE8

    大家都知道canvas是个非常好玩的东西,但是IE9以下的浏览器不支持,有时候业务需求必须用到canvas,且又要求兼容IE8浏览器,那怎么办呢? 1.添加对html5的支持:<!--[if I ...