Android Servie AIDL 复杂数据

上一章节中我们传递的是 int 类型的参数,然后服务端返回一个 String 类型的参数,很简单,但是实际开发中,传递的往往是复杂的数据类型

本章节我们就来学习如何使用 AIDL Service 向服务端传递复杂数据类型的数据

Parcelable 接口

ParcelableSerializable 一样,都是用于序列化的,只是 Parcelable 更加轻量级,速度更快

但是写起来就有点麻烦了,复杂无比,好在有工具 Android Parcelable Code Generator 来完成序列化

  1. 首先实现 writeToParcel()readFromPacel() 方法

    写入方法将对象写入到包裹 (parcel) 中

    读取方法则从包裹中读取对象

    注意: 写入属性顺序需与读取顺序相同

  2. 接着在该类中添加一个名为 CREATORstatic final 属性,该属性需要实现 android.os.Parcelable.Creator 接口

  3. 重写接口中的两个方法

    1. createFromParcel(Parcel source)

      方法实现从 source 创建出 JavaBean 实例的功能

    2. newArray(int size)

      创建一个类型为 T,长度为 size 的数组,只有一个简单的 return new T[size];

  4. 最后创建 describeContents() 直接返回 0 即可

注意

非原始类型 中除了 StringCharSequence 以外,其余均需要一个 方向指示符

方向指示符包括 inout 、和 inout

方向符 说明
in 表示由客户端设置
out 表示由服务端设置
inout 表示客户端和服务端都设置了该值

范例

自定义两种对象类型 Person 与 Salary

  1. Person 作为调用远程的 Service 的参数
  2. Salary 作为返回值

先来看看最后的效果图


创建服务端

  1. 创建一个 空的 Android 项目 cn.twle.android.MixedServer

  2. 创建 AIDL 目录,在 app 目录上点右键,选择 NEW -> Folder -> AIDL Folder 然后点 Finish

  3. app/aidl 目录下新建包 cn.twle.android.aidl

  4. app/aidl 目录下的包 cn.twle.android.aidl 上点右键,然后选择 New->AIDL->AIDL File 分别创建两个文件 Person.aidlSalary.aidl

    它们需要实现 Parcelable 接口

    Person.aidl

    parcelable Person;
    

    Salary.aidl

    parcelable Salary;
    
  5. app/aidl 目录下的包 cn.twle.android.aidl 上点右键,然后选择 New->AIDL->AIDL File 创建文件 ISalary.aidl 在里面写一个简单的获取工资信息的方法

    package cn.twle.android.aidl;
    
    import cn.twle.android.aidl.Salary;  
    import cn.twle.android.aidl.Person;  
    interface ISalary  
    {  
        //定义一个Person对象作为传入参数  
        //接口中定义方法时,需要制定新参的传递模式,这里是传入,所以前面有一个in
    
        Salary getMsg(in Person owner);  
    }
    
  6. 然后点击 Build->Make Project 先生成我们需要的 ISalary.java 这时候会报错,提示 Person.javaSalary.java 不存在,没关系

  7. app/java 目录下新建包 cn.twle.android.aidl

  8. app/java 的包 cn.twle.android.aidl 创建文件 Person.javaSalary.java ,需要实现 Parcelable 接口,重写对应的方法

    因为我们后面是根据 Person 对象来获取 Map 集合中的数据,所以 Person.java 中我们重写了 hashcode 和 equals 的方法;而 Salary 类则不需要

    Person.java

    package cn.twle.android.aidl;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class Person implements Parcelable{
    
        private Integer id;
        private String name;
    
        public Person() {}
    
        public Person(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        //实现 Parcelable 必须实现的方法
        @Override
        public int describeContents() {
            return 0;
        }
    
        //写入数据到Parcel中的方法
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            //把对象所包含的数据写入到parcel中
            dest.writeInt(id);
            dest.writeString(name);
        }
    
        //必须提供一个名为CREATOR的static final属性 该属性需要实现
        //android.os.Parcelable.Creator<T> 接口
        public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
            //Parcel中读取数据,返回Person对象
            @Override
            public Person createFromParcel(Parcel source) {
                return new Person(source.readInt(),source.readString());
            }
            @Override
            public Person[] newArray(int size) {
                return new Person[size];
            }
        };
    
        //因为我们集合取出元素的时候是根据Person对象来取得,所以比较麻烦,
        //需要我们重写hashCode()equals()方法
        @Override
        public int hashCode()
        {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Person other = (Person) obj;
            if (name == null)
            {
                if (other.name != null)
                    return false;
            }
            else if (!name.equals(other.name))
                return false;
            return true;
        }
    }
    

    Salary.java

    package cn.twle.android.aidl;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class Salary implements Parcelable {
    
        private String type;
        private Integer salary;
    
        public Salary() {
        }
    
        public Salary(String type, Integer salary) {
            this.type = type;
            this.salary = salary;
        }
    
        public String getType() {
            return type;
        }
    
        public Integer getSalary() {
            return salary;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public void setSalary(Integer salary) {
            this.salary = salary;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(type);
            dest.writeInt(salary);
        }
    
        public static final Parcelable.Creator<Salary> CREATOR = new Parcelable.Creator<Salary>() {
            //Parcel中读取数据,返回Person对象
            @Override
            public Salary createFromParcel(Parcel source) {
                return new Salary(source.readString(), source.readInt());
            }
    
            @Override
            public Salary[] newArray(int size) {
                return new Salary[size];
            }
        };
    
        public String toString() {
            return "工作:" + type + "    薪水: " + salary;
        }
    }
    
  9. 然后点击 Build-> rebuild project 重新编译,这时候是成功的

  10. MainActivity.java 目录下新建文件 MsAidlService.java

    定义一个 SalaryBinder 类继承 Stub,从而实现 ISalary 和 IBinder 接口;定义一个存储信息的 Map 集合

    重载 onBind() 方法,返回 SalaryBinder 类的对象实例

    package cn.twle.android.mixedserver;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import cn.twle.android.aidl.ISalary.Stub;
    import cn.twle.android.aidl.Person;
    import cn.twle.android.aidl.Salary;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class MsAidlService extends Service {
    
        private SalaryBinder salaryBinder;
        private static Map<Person,Salary> ss = new HashMap<Person, Salary>();
        //初始化Map集合,这里在静态代码块中进行初始化,当然你可也以在构造方法中完成初始化
        static
        {
            ss.put(new Person(1, "jav"), new Salary("码农", 2000));
            ss.put(new Person(2, "gen"), new Salary("歌手", 20000));
            ss.put(new Person(3, "xm"), new Salary("学生", 20));
            ss.put(new Person(4, "mrwang"), new Salary("老师", 2000));
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            salaryBinder = new SalaryBinder();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return salaryBinder;
        }
    
        //同样是继承Stub,即同时实现ISalary接口和IBinder接口
        public class SalaryBinder extends Stub
        {
    
            @Override
            public Salary getMsg(Person owner) throws RemoteException {
                return ss.get(owner);
            }
    
        }
    
        @Override
        public void onDestroy() {
            System.out.println("服务结束!");
            super.onDestroy();
        }
    
    }
    
  11. 修改 AndroidManifest.xml 注册 Service

    <service android:name=".MsAidlService">  
        <intent-filter>    
            <action android:name="cn.twle.android.aidl.MsAidlService" />  
            <category android:name="android.intent.category.DEFAULT" />  
        </intent-filter>    
    </service>
    

先运行一下

客户端

  1. 创建一个 空的 Android 项目 cn.twle.android.MixedClient

  2. 重复上面的 [2-9] 步骤

  3. 先 build 一下

  4. 修改 activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="请输入要查询的人的姓名" />
    
        <EditText
            android:id="@+id/ipt_search"
            android:inputType="text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <Button 
            android:id="@+id/btn_query"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="查询"/>
    
        <TextView 
            android:id="@+id/txt_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    
  5. 修改 MainActivity.java 定义一个 ServciceConnection 对象, 重写对应方法,和前面的普通数据的类似

    package cn.twle.android.mixedclient;
    
    import cn.twle.android.aidl.ISalary;  
    import cn.twle.android.aidl.Person;  
    import cn.twle.android.aidl.Salary;
    
    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;  
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
        private ISalary salaryService;  
        private Button btn_query;  
        private EditText ipt_search;  
        private TextView txt_show;  
        private ServiceConnection conn = new ServiceConnection() {
    
            @Override  
            public void onServiceDisconnected(ComponentName name) {  
                salaryService = null;  
            }
    
            @Override  
            public void onServiceConnected(ComponentName name, IBinder service) {  
                //返回的是代理对象,要调用这个方法哦!  
                salaryService = ISalary.Stub.asInterface(service);  
            }  
        };
    
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_main);
    
            btn_query  = (Button)   findViewById(R.id.btn_query);  
            ipt_search = (EditText) findViewById(R.id.ipt_search);  
            txt_show   = (TextView) findViewById(R.id.txt_show);
    
            Intent it = new Intent("cn.twle.android.aidl.MsAidlService");  
            it.setPackage("cn.twle.android.mixedserver");  
            bindService(it, conn, Service.BIND_AUTO_CREATE);
    
            btn_query.setOnClickListener(new OnClickListener() {           
                @Override  
                public void onClick(View v) {  
                    try  
                    {  
                        String name = ipt_search.getText().toString();  
                        Salary salary = salaryService.getMsg(new Person(1,name));  
                        txt_show.setText(name + salary.toString());  
                    }catch(RemoteException e){e.printStackTrace();}  
                }  
            });
    
        }  
        @Override  
        protected void onDestroy() {  
            super.onDestroy();  
            this.unbindService(conn);  
        }
    
    }
    

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.