打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Binder与AIDL服务

服务(Service)是Android系统中4个应用程序组件之一。服务主要用于两个目的:后台运行和跨进程访问。通过启动一个服务,可以在不显示界面的前提下在后台运行指定的任务,这样可以不影响用户做其他事情。通过AIDL服务可以实现不同进程之间的通信,这也是服务的重要用途之一。

跨进程访问(AIDL服务)

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。Activity和Broadcast都可以跨进程通信,除此之外,还可以使用Content Provider进行跨进程通信。现在我们已经了解了4个Android应用程序组件中的3个(Activity、Broadcast和Content Provider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。这就是本节要介绍的AIDL服务。

什么是AIDL服务

本章前面的部分介绍了开发人员如何定制自己的服务(startService,bindService),但这些服务并不能被其他的应用程序访问。为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。

建立AIDL服务的步骤:

建立AIDL服务要比建立普通的服务复杂一些,具体步骤如下:

(1)在Eclipse Android工程的Java包目录中建立一个扩展名为aidl的文件。该文件的语法类似于Java代码,但会稍有不同。详细介绍见后面实例的内容。

(2)如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java)。

(3)建立一个服务类(Service的子类)。

(4)实现由aidl文件生成的Java接口。

(5)在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。

本例中将建立一个简单的AIDL服务。这个AIDL服务只有一个getValue方法,该方法返回一个String类型的值。在安装完服务后,会在客户端调用这个getValue方法,并将返回值在TextView组件中输出。建立这个AIDL服务的步骤如下:

(1)建立一个aidl文件。在Java包目录中建立一个IMyService.aidl文件。IMyService.aidl文件的位置如图所示。

IMyService.aidl文件的内容如下:

package com.anjoyo.aidl.remote;

interface IMyService {     String getValue(); }

(2)编写一个MyService类。MyService是Service的子类,在MyService类中定义了一个内嵌类(MyServiceImpl),该类是IMyService.Stub的子类。MyService类的代码如下:

public class MyService extends Service  {       public class MyServiceImpl extends IMyService.Stub{          @Override          public String getValue() throws RemoteException{              return "AIDL远程访问";          }      }      @Override      public IBinder onBind(Intent intent) {                  return new MyServiceImpl();      }  }

在编写上面代码时要注意如下两点:

IMyService.Stub是根据IMyService.aidl文件自动生成的,一般并不需要管这个类的内容,只需要编写一个继承于IMyService.Stub类的子类(MyServiceImpl类)即可。

onBind方法必须返回MyServiceImpl类的对象实例,否则客户端无法获得服务对象。

(3)在AndroidManifest.xml文件中配置MyService类,代码如下:

<service android:name=".MyService" >     <intent-filter>           <action android:name="com.anjoyo.aidl.IMyService" />     </intent-filter> </service>

其中"com.anjoyo.aidl.IMyService"是客户端用于访问AIDL服务的ID。

服务端写完!!!

下面来编写客户端的调用代码。首先新建一个Eclipse Android工程,并将自动生成的IMyService.java文件连同包目录一起复制到工程的src目录中,如图所示。

调用AIDL服务首先要绑定服务,然后才能获得服务对象,代码如下:

传递复杂数据的AIDL服务

AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。AIDL服务支持的数据类型如下:

Java的简单类型(int、char、boolean等)。不需要导入(import)。

String和CharSequence。不需要导入(import)。

List和Map。但要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入(import)。

AIDL自动生成的接口。需要导入(import)。

实现android.os.Parcelable接口的类。需要导入(import)。

其中后两种数据类型需要使用import进行导入,将在本章的后面详细介绍。

传递不需要import的数据类型的值的方式相同。传递一个需要import的数据类型的值(例如,实现android.os.Parcelable接口的类)的步骤略显复杂。除了要建立一个实现android.os.Parcelable接口的类外,还需要为这个类单独建立一个aidl文件,并使用parcelable关键字进行定义。具体的实现步骤如下:

(1)建立一个IMyService.aidl文件,并输入如下代码:

package com.example.day0108_aidl;import com.example.day0108_aidl.Product;interface IMyService{    String getValue(in Product p);     Product getProduct(); }

在编写上面代码时要注意如下两点:

Product是一个实现android.os.Parcelable接口的类,需要使用import导入这个类。

如果方法的类型是非简单类型,例如,String、List或自定义的类,需要使用in、out或inout修饰。其中in表示这个值被客户端设置;out表示这个值被服务端设置;inout表示这个值既被客户端设置,又被服务端设置。

(2)编写Product类。该类是用于传递的数据类型,代码如下:

package com.example.day0108_aidl;import android.os.Parcel;import android.os.Parcelable;public class Product implements Parcelable {    private int id;    private String name;    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(id);        dest.writeString(name);    }    public Product(){    }     public Product(Parcel in){        this.id=in.readInt();        this.name=in.readString();    }        public static final Parcelable.Creator<Product> CREATOR=new Creator<Product>() {                @Override        public Product[] newArray(int size) {            return new Product[size];        }                @Override        public Product createFromParcel(Parcel source) {            return new Product(source);        }    };    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "Product [id=" + id + ", name=" + name + "]";    }}

在编写Product类时应注意如下3点:

Product类必须实现android.os.Parcelable接口。该接口用于序列化对象。在Android中之所以使用Pacelable接口序列化,而不java.io.Serializable接口,是因为Google在开发Android时发现Serializable序列化的效率并不高,因此,特意提供了一个Parcelable接口来序列化对象。

在Product类中必须有一个静态常量,常量名必须是CREATOR,而且CREATOR常量的数据类型必须是Parcelable.Creator。

在writeToParcel方法中需要将要序列化的值写入Parcel对象。

(3)建立一个Product.aidl文件,并输入如下内容:

parcelable Product;

建立AIDL服务的步骤(3)

(4)编写一个MyService类,代码如下:

package com.anjoyo.remote.aidl; 

//  AIDL服务类

package com.example.day0108_aidl;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class MyService extends Service {    class MyBinder extends IMyService.Stub{            @Override        public Product getProduct() throws RemoteException {            Product p=new Product();            p.setId(1);            p.setName("测试");            return p;        }        @Override        public String getValue(Product p) throws RemoteException {            p.setName(p.getName()+"我又回来了");            return p.toString();        }            }    @Override    public IBinder onBind(Intent intent) {        return new MyBinder();    }}

(5)在AndroidManifest.xml文件中配置MyService类,代码如下:

<service android:name=".MyService" >     <intent-filter>           <action android:name="com.anjoyo.remote.aidl.IMyService" />     </intent-filter> </service>

在客户端调用AIDL服务的方法与第一个实例介绍的方法相同,首先将IMyService.java和Product.java文件复制到客户端工程,然后绑定AIDL服务,并获得AIDL服务对象,最后调用AIDL服务中的方法。完整的客户端代码如下:

package com.example.day0108_test;import com.example.day0108_aidl.IMyService;import com.example.day0108_aidl.Product;import android.app.Activity;import android.content.ComponentName;import android.content.Context;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.TextView;public class MainActivity extends Activity {    private TextView textView;    private Button button;    IMyService myService;    private ServiceConnection conn = new ServiceConnection() {                @Override        public void onServiceDisconnected(ComponentName name) {                    }                @Override        public void onServiceConnected(ComponentName name, IBinder service) {            myService=IMyService.Stub.asInterface(service);        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        textView=((TextView) findViewById(R.id.textView1));        button=(Button) findViewById(R.id.button1);        button.setOnClickListener(new OnClickListener() {                        @Override            public void onClick(View v) {                try {                    Product p=new Product();                    p.setId(2);                    p.setName("测试");                    textView.setText(myService.getProduct().toString()+myService.getValue(p).toString());                } catch (RemoteException e) {                    e.printStackTrace();                }            }        });        bindService(new Intent("com.yjy.service"), conn, Context.BIND_AUTO_CREATE);    }}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android 使用【AIDL】调用外部服务
android跨进程通信(IPC):使用AIDL
[z]Android Service学习之AIDL, Parcelable和远程服务
Android AIDL(Android Interface Definition Language)介绍
aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法
Android 中的AIDL
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服