Android--Service之AIDL传递系统基本类型数据
前言
前面讲解了Service的一些基本内容。但是对于绑定服务传递数据,只局限于本地服务,无法使用服务进行跨进程间的交互。如果需要用到跨进程交互的话,需要用到一个新的技术-AIDL,这篇博客就针对AIDL如何传递内置类型数据进行讲解。对于Service不熟悉的朋友,可以先看看之前的博客:Service基础、Service高级、Service应用。
本篇博客内容如下:
什么是AIDL?
先来回顾一下,Android在本地的Service中如何与其它组件进行交互的,首先Service必须实现其onBind()方法,然后在onBind方法传递一个IBinder接口的实现,而在其它组件中使用bindService()绑定一个服务,再通过其中的参数ServiceConnection对象获取到Service中定义的IBinder接口的实现。那么与Service进行数据交互,其实就是传递一个IBinder,通过这个IBinder进行交互。
而现在就碰到一个问题,在同一个进程中,是可以获取到这个Service类的,也就可以获得这个Service中定义的IBinder,但是如果在不同的应用中,即远程服务,如何获取IBinder呢?仅仅是在不同的应用定义一相同的类是没有用的,所以Android为我们提供了AIDL语言,它需要先定义一个远程调用接口,然后为该接口提供一个实现类,通过共享这个远程调用接口来达到进程间数据交互的目的,而这个接口的代码是有很多共性的,并且编写过程相当枯燥乏味,所以Android开发者为我们提供了ADIL来简化通讯接口的开发。
AIDL(Android Interface Definition Language)是Android远程调用接口的定义语言。它有它自己的一套语法规范,但是和Java类似,这并不难理解,详细的这个会后面介绍。而当你定义好一个AIDL接口之后,你会发现在gen/目录下,多出一个与定义的AIDL包名相同,文件名相同的一个Java类,这个类是编译器根据定义的AIDL接口自动生成的代码,观察之后发现其实它也是继承了Binder类(Binder是IBinder的实现类),所以它可以通过ServiceConnection进行数据传递。Service只需要暴露这个AIDL接口给客户端,让客户端也定义它,这样两个应用进程就可以通讯了。
如何定义AIDL?
AIDL的语法与Java接口的语法非常相似,但是存在一些差异:
- AIDL定义接口的源代码后缀必须以.aidl结尾。
- AIDL一样要指定AIDL接口的包信息package *。
- AIDL接口无需指定public、private、protected等作用域,可以理解为就是public。
- AIDL默认情况下只能传递基本类型、String、List、Map、CharSequence。
- 如果需要传递其他类型的对象,需要import对象的包名,并需要对对象进行特殊处理(之后会介绍)。
例如:
package com.example.aidlservicedemo.domain; interface IDog{
String getName();
int getAge();
}
ADIL做了什么?
当你声明完一个AIDL接口的时候,你会发现在项目的gen/目录下,对应包中存在一个同名的Java文件,这个文件是Android帮我们自动生成的,里面有很多代码,这里只讲一下需要注意的。查看自动生成的这个Java文件代码,会发现它定义了一个名为Stub的静态抽象类,这个Stub继承了Binder,实现了AIDL接口,当然其中也实现了AIDL接口的两个方法,粗略看一下会发现它对数据做了一个序列化和反序列化的操作。正因为AIDL对数据进行了序列化和反序列化,所以才可以在进程间传递。
使用ADIL传递系统基本数据
定义好AIDL接口之后,就需要通过服务把接口暴露给客户端,这里Service.onBind()传递的就是这个Stub静态抽象类的实现类,其他没什么特别的。
下面通过一个Demo来演示ADIL如何传递数据的,在示例中,给出两个应用,分别实现Server与调用客户端,使用的AIDL接口就是上面给出的AIDL示例代码,这里不再重复定义。
AIDL服务:BaseTypeService.java
package com.example.aidlservicedemo; import java.util.Random; import com.example.aidlservicedemo.domain.IDog.Stub; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log; public class BaseTypeService extends Service {
private final String TAG="main";
private DogBinder binder=null;
private String[] names=new String[]{"小白","旺财","小黑"};
private int[] ages=new int[]{1,2,3}; /**
* Stub的实现类,Stub内部实现了Binder
* 内部实现AIDL定义的方法
*/
public class DogBinder extends Stub{ @Override
public String getName() throws RemoteException {
Random random=new Random();
int nextInt = random.nextInt(2);
return names[nextInt];
} @Override
public int getAge() throws RemoteException {
Random random=new Random();
int nextInt = random.nextInt(2);
return ages[nextInt];
}
} @Override
public void onCreate() {
super.onCreate();
// 实例化Binder对象
binder=new DogBinder();
Log.i(TAG, "创建服务成功");
} @Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "绑定服务成功");
// 返回Binder对象
return binder;
}
}
客户端调用服务获取数据:
package com.example.aidlClientdemo; import com.example.aidlservicedemo.domain.IDog;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; public class BaseTypeActivity extends Activity {
private Button btn_startService, btn_endService,btn_getServiceData;
private IDog dogService; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service); btn_startService = (Button) findViewById(R.id.btn_startService);
btn_endService = (Button) findViewById(R.id.btn_endService);
btn_getServiceData = (Button) findViewById(R.id.btn_getServiceData); btn_startService.setOnClickListener(click);
btn_endService.setOnClickListener(click);
btn_getServiceData.setOnClickListener(click);
} private View.OnClickListener click = new OnClickListener() { @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_startService:
startService();
break;
case R.id.btn_endService:
endService();
break;
case R.id.btn_getServiceData:
getServiceDate();
break;
}
}
};
/*
* 获取数据
*/
private void getServiceDate() {
try {
if(dogService!=null){
StringBuilder sBuilder=new StringBuilder();
sBuilder.append("name:"+dogService.getName());
sBuilder.append("\nage:"+dogService.getAge());
Toast.makeText(BaseTypeActivity.this, sBuilder.toString(), Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(BaseTypeActivity.this, "请先绑定服务", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
} private ServiceConnection connBase=new ServiceConnection() { @Override
public void onServiceDisconnected(ComponentName name) {
dogService=null;
} @Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IDog.Stub.asInterface,获取接口
dogService=IDog.Stub.asInterface(service);
}
}; /**
* 开始服务
*/
private void startService(){
Intent intent=new Intent();
intent.setAction("cn.bgxt.Service.BASE_TYPE_SERVICE");
bindService(intent, connBase, BIND_AUTO_CREATE);
Toast.makeText(BaseTypeActivity.this, "开始绑定服务", Toast.LENGTH_SHORT).show();
}
/**
* 停止服务
*/
private void endService(){
if(connBase!=null)
{
unbindService(connBase);
// 接触绑定的时候需要回收dogService连接资源
// 在源码中漏了,这是后来加上的
dogService=null;
Toast.makeText(BaseTypeActivity.this, "服务解除绑定", Toast.LENGTH_SHORT).show();
}
}
}
效果展示:先运行服务应用,再运行客户端应用。
总结
本篇博客只介绍了AIDL的基本结构,以及如何通过AIDL接口传递一个系统内置类型的数据。下一篇博客将介绍一下AIDL的高级应用,如何传递一个自定义对象。
Android--Service之AIDL传递系统基本类型数据的更多相关文章
- Android service binder aidl 关系
/********************************************************************************** * Android servic ...
- [Android] Android GreenDao 保存 JavaBean 或者List <JavaBean>类型数据
Android GreenDao 保存 JavaBean 或者List <JavaBean>类型数据 简介 数据库存储数据基本上每个APP都有用到,GreenDAO 是一个将对象映射到 S ...
- 【5】Android Service 与 AIDL
前言:本系列仅介绍基本大体的使用步骤,而不对每个步骤进行细致的讲解.读者可作为已经对相关内容有所了解后的快速查阅. 一.单应用内Service的使用 Service组件与Activity以IBinde ...
- Android--Service之AIDL传递复杂对象
前言 Android的AIDL不仅可以在绑定服务中传递一些Android规定的数据类型的数据,还可以传递一些复杂类型的数据.但是与传递系统允许的数据类型相比,复杂类型数据的传递要做更多的工作,本篇博客 ...
- Android AIDL Service 跨进程传递复杂数据
黑夜 黑夜给了我黑色的眼睛,我却用它寻找光明~ 传值方式 AIDL是同意跨进程传递值的,一般来说有三种方式: - 广播:这样的算是比較常见的一种方式了,传递小数据不错 - 文件:这个是保存到文件里.然 ...
- SpringMVC 处理Date类型数据@InitBinder @DateTimeFormat 注解 的使用
使用SpringMVC的时候,需要将表单中的日期字符串转换成对应JavaBean的Date类型,而SpringMVC默认不支持这个格式的转换,解决方法有两种,如下: 方法一 . 在需要日期转换的Con ...
- MySQL中enum类型数据,要传入字符串
问题来源:公司业务,某张表中一个字段定义为: enum('0','1','2','3','4','5','6','7','8','9','10') NOT NULL DEFAULT '0' 某天跑脚本 ...
- Android学习笔记_23_服务Service之AIDL和远程服务实现进程通信以及进程间传递自定义类型参数
一.了解AIDL语言: 在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的.因此要传递对象, 需要把对象解析 ...
- Android Service学习之AIDL, Parcelable和远程服务
AIDL的作用 由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象.在Android平台,一个进程通常不能访问另一个进程的内存空 ...
随机推荐
- AJAX随笔1
[1] AJAX简介 > 全称: Asynchronous JavaScript And XML > 异步的JavaScript和XML > AJAX就是通过JavaSc ...
- STL之vector容器详解
vector 容器 vector是C++标准模版库(STL,Standard Template Library)中的部分内容.之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说: ...
- 第45章:MongoDB-集群--Sharding(分片)--分片的管理
①列出所有的Shard db.runCommand({“listshards”:1}); ②查看分片信息 db.printShardingStatus(); ③判断是否分片 db.runCommand ...
- STM32CubeMX+Keil裸机代码风格(1)
1.打开STM32CubeMX,New project 选好自己要用的芯片 2.选上左侧SYS中的debug Serial Wire(定义烧程序的端口) . 3,选上左侧TIM6,使TIM6可用(TI ...
- python读取文件时提示"UnicodeDecodeError: 'gbk' codec can't decode
解决办法1. FILE_OBJECT= open('order.log','r', encoding='UTF-8') 解决办法2. FILE_OBJECT= open('order.log','rb ...
- Sqlalchemy python经典第三方orm
Ⅰ. 安装 pip install sqlalchemy Ⅱ. 起步链接 import time import threading import sqlalchemy from sqlalchemy ...
- 更改MySQL/Postgresql密码
Parrot包括几个SQL引擎,但是当它们被预先安装时,默认密码未被配置,并且拒绝访问其root用户. 重新配置Mysql / Mariadb密码 停止MySQL服务. sudo service my ...
- 从git远程仓库Checkout项目到本地
一.登录coding 并且项目已创建好 已经是项目的组员 二.打开idea 1.弹出如下页面 复制远程项目上的SSH(URL)到下框URL 并且Test测试 成功就Clone即可 2.Clone ...
- Codeforces Round #421 (Div. 2)
A: 题意:给你一本书共c页,第一天看v0页,第二天看v0+a,第二天看v0+2a以此类推,每天最多看v1页,但是后一天要重复看前一天的后l页. 代码: #include<stdio.h> ...
- Qt Creator快捷键设置
QT Creator 下载地址 http://download.qt.io/ 一.快捷键配置方法: 进入“工具->选项->环境->键盘”即可配置快捷键. 二.常用默认快捷键: 编 ...