Android学习笔记二十六.跨进程调用Service(AIDL Service)

跨进程调用Service(AIDL Service)

一、AIDL Service

1.什么是AIDL Service?

AIDL,即Android Interface Definition Language.是Android用于定义远程接口,AIDL接口定义语言的语法比较简单,这种接口定义语言并不是真正的编程语言,它只是定义两个进程之间的通信接口。AIDL的语法与Java接口很相似,但存在如下几点差异:

(1)AIDL定义接口的源代码必须以.aidl结尾;

(2)AIDL接口中用到数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导包,即使他们在同一个包中也需要导包。

在Android系统中,由于各个应用程序都是运行在自己的进程中(启动一个应用即启动一个进程),进程之间一般无法直接进行数据交换。所以,为了实现进程之间的通信(interprocess
communiocation,简称IPC),Android提供了AIDL Service。

2.远程Service

与本地Service相对应的是远程Service,即一个应用程序(进程)可以访问另一个应用程序的Service组件前者我们称之为客户端、后者为服务端,而客户端访问服务端就是通过AIDL接口实现彼此间通信的。通过之前几篇文章我们知道,客户端访问Service时,Android并不是直接返回Service对象给客户端,而是将Service的代理对象(IBinder对象)通过Service的onBind()方法返回给客户端,因此,Android的AIDL远程接口的实现类就是那个IBinder实现类。当客户端获取了远程Service的IBinder对象的代理之后,客户端进程就可通过该IBinder对象去回调远程Service的属性或方法,从而实现进程间的通信。

3.Service返回的IBinder对象

当访问者(客户端)调用bindService()方法来绑定与启动指定的Service,对于绑定本地Service还是绑定远程Service,Service返回的IBinder对象是有所区别的。

(1)绑定本地Service:本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnection对象的onServiceConnected方法的第二个参数;

(2)绑定远程Service:远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection对象的onServiceConnected方法的第二个参数。

4.AIDL接口工作原理

当在工程中实现了一个.aidl的AIDL接口源文件(如/src/com/android_aidlservice/ICat.aidl),我们可以通过两种方式生成需要的ICat.java接口文件:一是使用Android SDK安装目录下的platform-tools子录下的aidl.exe工具;二是ADT工具自动为该AIDL接口生成实现(路径:gen/com.example.android_aidlservice/ICat.java)。ICat.java接口包含一个Stub内部类,该内部类实现了IBinder、ICat两个接口,这个Stub类将会作为远程Service的回调类---它实现了IBinder接口,因此可作为Service的onBind()方法的返回值。

二、进程间通信开发思路

1.服务端-远程Service开发

(1)定义一个AIDL接口,文件名为xxx.aidl,保存到源码所在的路径,如/src/com/android_aidlservice/ICat.aidl;

package com.example.android_aidlservice;

interface ICat

{

String getColor();

double getWeight();

}

其中,com.example.android_aidlservice为其所在的包名。

(2)定义一个Service实现类,并实现一个内部类继承于Stub即实现了ICat接口,也就实现了IBinder接口。该Service的onBind()方法所返回的IBinder对象为ICat.Stub的子类的实例。

private CatBinder catBinder;

public class CatBinder extends Stub

{

......

}

@Override

public IBinder onBind(Intent arg0)

{

return catBinder;

}

(3)在AndroidMainfest.xml工程文件中配置该Service

<application .... >

<!--定义一个Service组件-->

<service android:name=".AidlService">

<intent-filter>

<action android:name="com.example.sercie.AIDL_SERVICE"></action>

</intent-filter>

</service>

</application>

2.客户端开发思路

(1)定义一个AIDL接口,文件名为xxx.aidl,保存到源码所在的路径,如/src/com/android_aidlservice/ICat.aidl;

package com.example.android_aidlservice;

interface ICat

{

String getColor();

double getWeight();

}

其中,com.example.android_aidlservice为其所在的包名,该.aidl文件为从Service段的AIDL接口文件复制到客户端应用中。

(2)创建ServiceConnection对象,并在ServiceConnection对象的onServiceConnected方法中添加如下代码:

catService = ICat.Stub.asInterface(service);

其中,catService为Service的onBind()方法返回IBinder对象的代理。

(3)以ServiceConnection对象作为参数,调用Context的bindService()方法绑定并启动远程Service即可。

三、源码实现

1.服务端

(1)定义一个Service实现类-/src/com/example/android_service/AidlService.java

package com.example.android_aidlservice;
import java.util.Timer;
import java.util.TimerTask;
import com.example.android_aidlservice.ICat.Stub;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class AidlService extends Service {
 //1.声明一个IBinder对象、Timer对象
 private CatBinder catBinder;
 private Timer timer;
 //2.定义两个数组与两个私有变量
 private String color;
 private double weight;
 String[] colors = new String[]{"黑色","黄色","红色"};
 double[] weigths=new double[]{2.3,3.1,1.58};
 //3.继承stub,也就实现了ICat接口,并实现了IBinder接口
 public class CatBinder extends Stub
 {
  @Override
  public String getColor() throws RemoteException {
   return color;
  }
  @Override
  public double getWeight() throws RemoteException {
   return weight;
  }

 }
 //4.当Service创建时调用该方法
 @Override
 public void onCreate() {
  super.onCreate();
  //a.实例化一个CatBinder对象
  catBinder = new CatBinder();
  //b.该service完成的任务:随机地改变Service组件内color、weight属性的值
  timer.schedule(new TimerTask(){
   @Override
   public void run() {
    int rand=(int)(Math.random()*3);
    color=colors[rand];
    weight = weigths[rand];
    System.out.println("-----------"+rand);
   }
  }, 0, 800);
 }
 /*5.访问者使用bindService()方法启动Service时,该方法用于返回catBinder对象
  * (1)在绑定本地Service的情况下,该catBinder对象会直接传给客户端的ServiceConnection对象;
  * (2)在绑定远程Service的情况下,只将catBinder对象的代理传递给客户端的ServiceConnection对象的
  * onServiceConnection方法的第二个参数*/
 @Override
 public IBinder onBind(Intent intent) {
  return catBinder;
 }
 //6.回调该方法关闭Service
 @Override
 public void onDestroy() {
  timer.cancel();
 }
}

(2)在AndroidManifest文件中配置该Service

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android_aidlservice"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service android:name=".AidlService"
              android:exported="true">
            <intent-filter>
                <action android:name="com.example.service.AIDL_SERVICE"/>
            </intent-filter>
        </service>
    </application>
</manifest>

2.客户端

(1)定义一个Activity实现类-/src/com/example/android_service/AidlClient.java

package com.example.android_aidl_service;
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.Button;
import android.widget.EditText;
public class AidlClient extends Activity {
 private ICat catService;	//声明一个ICat对象
 private Button get;
 private EditText color,weight;

 //1.创建一个ServiceConnection对象
 private ServiceConnection conn=new ServiceConnection(){
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   //获取远程Service的onBind方法的对象的代理
   catService = ICat.Stub.asInterface(service);
  }
  @Override
  public void onServiceDisconnected(ComponentName name) {
   catService=null;
  }
 };

 //2.绑定远程Service并获取其内容
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  //a.获取Activity主界面组件
  setContentView(R.layout.main);
  get=(Button)findViewById(R.id.get);
  color=(EditText)findViewById(R.id.color);
  weight=(EditText)findViewById(R.id.weight);

  //b.创建所需绑定的Service的Intent并设置其Action属性(即指定启动哪个远程Service)
  Intent intent=new Intent();
  intent.setAction("com.example.service.AIDL_SERVICE");
  //c.绑定并启动远程Service
  bindService(intent,conn,Service.BIND_AUTO_CREATE);
  //d.通过IBinder对象的代理获取远程Service数据
  get.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View v)
   {
    try
    {
     color.setText(catService.getColor());
     weight.setText(catService.getWeight()+"");
    }
    catch (RemoteException e) {
     e.printStackTrace();
    }
   }
  });
 }
 //3.退出Activity时调用该方法,解除远程Service的绑定
 @Override
 protected void onDestroy() {
  super.onDestroy();
  this.unbindService(conn);
 }

}

(2)在AndroidManifest文件中配置该Activity

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android_aidl_service"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".AidlClient"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

效果:运行客户端程序,单击程序界面中"获取远程Service的数据"按钮,就会实现客户端读取远程Service功能。

时间: 2024-08-06 11:54:55

Android学习笔记二十六.跨进程调用Service(AIDL Service)的相关文章

Android学习笔记二十五之ListView多布局实现

Android学习笔记二十五之ListView多布局实现 这一节是介绍ListView这个控件的最后一节,实现一个Item的多布局.像我们经常在用的各种即时通讯工具,QQ.微信等,假设他们的会话界面是ListView实现的,那么ListView就有多种Item布局,这一节,我们就来实现一个ListView的多种Item. 要实现ListView里面有多种Item,就要重写适配器的两个方法getViewTypeCount()和getItemViewType(int position),第一个方法是

Android学习笔记二十四之ListView列表视图二

Android学习笔记二十四之ListView列表视图二 前面一篇我们介绍了常用的几种适配器的简单实现和ListView的简单使用,这一篇中,我们介绍一下ListView的优化和一些其它的问题. ListView优化方法一 在ListView中,我们最常用的就是自定义Adapter,在我们自定义Adapter中,需要实现两个比较重要的方法getCount()和getView(),前者是负责计算ListView的总Item数,后者是生成Item,有多少个Item就会调用getView()方法多少次

Android学习笔记(十六)——碎片之间进行交互(附源码)

碎片之间进行交互 点击下载源码 很多时候,一个活动中包含一个或者多个碎片,它们彼此协作,向用户展示一个一致的UI.在这种情况下,碎片之间能进行通信并交换数据十分重要. 1.使用上一篇中创建的同一个项目,在fragment.xml中添加TextView的标识id: android:id="@+id/lblFragment1" 2.在fragment2.xml中添加一个Button,用于与fragment1进行交互: <Button android:id="@+id/btn

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

【Unity 3D】学习笔记二十六:unity游戏脚本(六)

在3D游戏世界中,任何一个游戏对象在创建的时候都会附带Transform(变换)组件,并且该组件是无法删除的,也不应该删除.在unity中,Transform面板一共有3个属性: Position  (位置) Rotation(旋转) Scale(缩放) 这三个值都是用来调整游戏对象在游戏界面中的位置,状态等相关参数. Position  (位置) 任何一个游戏对象的三维坐标都保存在Vector3容器中,该容器记录对象在X轴,Y轴,Z轴的坐标.一旦Vector33容器中的坐标发生变化,那么Sce

angular学习笔记(二十六)-$http(4)-设置请求超时

本篇主要讲解$http(config)的config中的timeout项: $http({ timeout: number }) 数值,从发出请求开始计算,等待的毫秒数,超过这个数还没有响应,则返回错误 demo: html: <!DOCTYPE html> <html ng-app = 'HttpGet'> <head> <title>18.4 $http(2)</title> <meta charset="utf-8"

Android学习笔记二十之Toast吐司、Notification通知、PopupWindow弹出窗

Android学习笔记二十之Toast吐司.Notification通知.PopupWindow弹出窗 Toast吐司 Toast吐司是我们经常用到的一个控件,Toast是AndroidOS用来显示消息的一种机制,它与Dialog不同,Toast不会获取到焦点,通常显示一段时间之后就会自动消失,下面我们来介绍Toast的几种常用方式: 第一种,默认显示方式,也是最常用的方式: Toast.makeText(MainActivity.this, "这是默认的显示方式", Toast.LE

马哥学习笔记二十六——MySQL主从复制

配置MySQL复制基本步骤: 一.master 1.启用二进制日志 log-bin = master-bin log-bin-index = master-bin.index 2.选择一个惟一server-id server-id = {0-2^32} 3.创建具有复制权限的用户 REPLICATION SLAVE REPLICATION CLIENT 二.slave 1.启用中继日志 relay-log = relay-log relay-log-index = 2.选择一个惟一的server

Android学习笔记(十六)——数据库操作(上)

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! Android 为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper帮助类, 借助这个类我们可以方便地对数据库进行创建和升级.首先,由于SQLiteOpenHelpe是一个抽象类,所以我们需要创建一个类来继承它.SQLiteOpenHelper 中有两个抽象方法,分别是onCreate()和 onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现