怎样用AIDL Service 传递复杂数据

简介: 怎样用AIDL Service 传递复杂数据

大家都知道在Android中通过AIDL可以跨进程调用Service中的数据,网上也有很多实例,但是大部分实例都是关于基本数据类型的远程调用,很少讲到复杂数据的调用,今天我用一个例子来演示一下怎样用AIDL Service 传递复杂数据。

我们分2步开始:

第一步:部署我们的服务端,也就是Service端:

1:在Service端我先自定义2个类型:Person和Pet。因为我们需要跨进程传递Person对象和Pet对象,所以Person类和Pet类都必须实现Parcelable接口,并要求在实现类中定义一个名为CREATER,类型为Parcelable.creator的静态Field。

代码如下:

package com.example.remoteservice;
 
import android.os.Parcel;
import android.os.Parcelable;
 
public class Person implements Parcelable {
    int id;
    String name;
    String pass;
 
    public Person() {
 
    }
 
    public Person(int id, String name, String pass) {
        this.id = id;
        this.name = name;
        this.pass = pass;
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
 
        if (getClass() != o.getClass()) {
            return false;
        }
        Person other = (Person) o;
 
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
 
        if (pass == null) {
            if (other.pass != null) {
                return false;
            }
        } else if (!pass.equals(other.pass)) {
            return false;
        }
 
        return true;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (name == null ? 0 : name.hashCode());
        result = prime * result + (pass == null ? 0 : pass.hashCode());
        return result;
    }
 
    @Override
    public int describeContents() {
 
        return 0;
    }
 
    @Override
    public void writeToParcel(Parcel arg0, int arg1) {
        arg0.writeInt(id);
        arg0.writeString(name);
        arg0.writeString(pass);
    }
 
    public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {
 
        @Override
        public Person createFromParcel(Parcel source) {
 
            return new Person(source.readInt(), source.readString(), source.readString());
        }
 
        @Override
        public Person[] newArray(int size) {
 
            return new Person[size];
        }
    };
 
    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;
    }
 
    public String getPass() {
        return pass;
    }
 
    public void setPass(String pass) {
        this.pass = pass;
    }
 
}

因为我们会对Person进行比较,所以在Person类中我重写了

public int hashCode() 和 public boolean equals(Object o)方法


package com.example.remoteservice;
 
import android.os.Parcel;
import android.os.Parcelable;
 
public class Pet implements Parcelable {
    String name;
    float weight;
 
    public Pet(String name, float weight) {
        this.name = name;
        this.weight = weight;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public float getWeight() {
        return weight;
    }
 
    public void setWeight(float weight) {
        this.weight = weight;
    }
 
    @Override
    public int describeContents() {
 
        return 1;
    }
 
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeFloat(weight);
 
    }
 
    public static final Parcelable.Creator<Pet> CREATOR = new Creator<Pet>() {
 
        @Override
        public Pet createFromParcel(Parcel source) {
 
            return new Pet(source.readString(), source.readFloat());
        }
 
        @Override
        public Pet[] newArray(int size) {
 
            return new Pet[size];
        }
    };
 
    @Override
    public String toString() {
 
        return "name:" + this.name + ";weight:" + this.weight;
    }
 
}

2:创建完自定义类型之后还需要用AIDL来定义它们,Person.aidl和Pet.aidl的代码如下:

Person.aidl

package com.example.remoteservice;
parcelable Person;

Pet.aidl


package com.example.remoteservice;
parcelable Person;

3:完成1,2之后就可以使用AIDL定义通信接口了,在这里我定义一个IPet.aidl的接口,代码如下:

package com.example.remoteservice; //必须导入包
import com.example.remoteservice.Person; //指定自定义类的位置
import com.example.remoteservice.Pet;
 
interface IPet
{
List<Pet> getPets(in Person owner);//这里的in表示Person对象是输入的参数
}

4:服务端的最后一步就是实现Service了,当然不要忘了注册Service,代码如下:

package com.example.remoteservice;
 
import com.example.remoteservice.IPet.Stub;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
 
public class RemoteService extends Service {
 
    private PetBinder petBinder;
 
    private static Map<Person, List<Pet>> pets = new HashMap<Person, List<Pet>>();
    static {
        ArrayList<Pet> list1 = new ArrayList<Pet>();
        list1.add(new Pet("candy", 2.2f));
        list1.add(new Pet("sandy", 4.2f));
        pets.put(new Person(1, "sun", "sun"), list1);
 
        ArrayList<Pet> list2 = new ArrayList<Pet>();
        list2.add(new Pet("moon", 5.2f));
        list2.add(new Pet("hony", 6.2f));
        pets.put(new Person(1, "csx", "csx"), list2);
 
    }
 
    public class PetBinder extends Stub {// 继承IPet接口中的Stub类,Stub类继承了Binder类,所有PetBinder也间接的继承了Binder类
 
        @Override
        public List<Pet> getPets(Person owner) throws RemoteException {
 
            return pets.get(owner);
        }
 
    }
 
    @Override
    public IBinder onBind(Intent intent) {
 
        Log.i("csx", "onBind");
        return petBinder;
    }
 
    @Override
    public void onCreate() {
 
        super.onCreate();
        Log.i("csx", "onCreate");
        petBinder = new PetBinder();// 实例化Binder
 
    }
 
    @Override
    public boolean onUnbind(Intent intent) {
 
        Log.i("csx", "onUnbind");
        return super.onUnbind(intent);
    }
 
    @Override
    public void onDestroy() {
 
        super.onDestroy();
        Log.i("csx", "onDestroy");
    }
 
}

这是我Service端的部署情况(其中MainActivity可以不用去实现,因为我们只提供服务,没有窗口显示):

第二步:部署客户端:

1.在客户端新建一个包,命名需要和服务端放置aidl文件的包名相同(我这里是com.example.remoteservice),然后把服务端的Person.java,Pet.java,Person.aidl,Pet.aidl,IPet.aidl复制到这个包下面

2.在activity中绑定远程服务进行数据交换,layout布局和activity代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.remoteclient.RemoteClient" >
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
 
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >
 
            <EditText
                android:id="@+id/editText_person"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:ems="10" >
            </EditText>
 
            <Button
                android:id="@+id/button_ok"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:text="确定" />
        </LinearLayout>
 
        <ListView
            android:id="@+id/listView_pet"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
        </ListView>
    </LinearLayout>
 
</RelativeLayout>

package com.example.remoteclient;
 
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.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
 
import com.example.remoteservice.IPet;
import com.example.remoteservice.Person;
import com.example.remoteservice.Pet;
 
import java.util.List;
 
public class RemoteClient extends ActionBarActivity {
 
    public static final String REMOTE_SERVICE_ACTION = "com.example.remoteservice.RemoteService.ACTION";
    EditText editText;
    Button button;
    ListView listView;
 
    IPet petService;// 声明IPet接口
    List<Pet> pets;
    ServiceConnection conn = new ServiceConnection() {
 
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("csx", "onServiceDisconnected");
            conn = null;
        }
 
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("csx", "onServiceConnected");
            petService = IPet.Stub.asInterface(service);// 通过远程服务的Binder实现接口
 
        }
    };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.remote_client_layout);
        editText = (EditText) findViewById(R.id.editText_person);
        button = (Button) findViewById(R.id.button_ok);
        listView = (ListView) findViewById(R.id.listView_pet);
 
        Intent service = new Intent();
        service.setAction(REMOTE_SERVICE_ACTION);
 
        bindService(service, conn, Service.BIND_AUTO_CREATE);// 绑定远程服务
 
        button.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                String personName = editText.getText().toString();
                if (personName == null || personName.equals("")) {
 
                    return;
                }
 
                try {
                    pets = petService.getPets(new Person(1, personName, personName));// 调用远程service的getPets方法
                    updataListView();
 
                } catch (RemoteException e) {
 
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
 
            }
        });
 
    }
 
    public void updataListView() {
        listView.setAdapter(null);
 
        if (pets == null || pets.isEmpty()) {
            return;
 
        }
        ArrayAdapter<Pet> adapter = new ArrayAdapter<Pet>(RemoteClient.this,
                android.R.layout.simple_list_item_1, pets);
        listView.setAdapter(adapter);
 
    }
 
    @Override
    protected void onDestroy() {
 
        unbindService(conn);// 解除绑定
        super.onDestroy();
    }
 
}

到此为止所有的工作都完成了,下面我们看一下效果:我在编辑框中输入“csx”,点击确定,就会显示出服务端RemoteService中pets的相应数据。

相关文章
王道408计组汇编语言部分学习总结
用于实现分支结构、循环结构的指令: cmp、 test、 jmp、 jxxx 用于实现函数调用的指令: push、pop、call、 ret 用于实现数据转移的指令: mov
680 0
|
Android开发
【Android 返回堆栈管理】打印 Android 中当前运行的 Activity 任务栈信息 | Activity 任务栈信息分析 | Activity 在相同 Stack 中的不同 Task(一)
【Android 返回堆栈管理】打印 Android 中当前运行的 Activity 任务栈信息 | Activity 任务栈信息分析 | Activity 在相同 Stack 中的不同 Task(一)
1319 0
【Android 返回堆栈管理】打印 Android 中当前运行的 Activity 任务栈信息 | Activity 任务栈信息分析 | Activity 在相同 Stack 中的不同 Task(一)
|
9月前
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
552 27
|
10月前
|
机器学习/深度学习 人工智能 算法
《当K12遇上朴素贝叶斯:趣味编程开启AI教育新旅程》
在数字化时代,K12教育迎来新机遇与挑战。编程教育作为培养逻辑思维和创新能力的关键,逐渐融入K12课程。朴素贝叶斯算法以其简单高效的特点,成为理想的入门算法。通过趣味编程如Scratch,结合生活实例、可视化工具和项目实践,激发学生兴趣,降低学习难度,提升其对机器学习的理解和应用能力。这不仅为学生打开人工智能的大门,也为未来科技发展奠定基础。
316 23
|
5月前
|
测试技术 API 开发者
淘宝关键词搜索商品列表API接入指南(含Python示例)
淘宝关键词搜索商品列表API是淘宝开放平台的核心接口,支持通过关键词检索商品,适用于比价、选品、市场分析等场景。接口提供丰富的筛选与排序功能,返回结构化数据,含商品ID、标题、价格、销量等信息。开发者可使用Python调用,需注意频率限制与错误处理,建议先在沙箱环境测试。
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
732 0
|
SQL 关系型数据库 MySQL
MySQL AUTO_INCREMENT 原理解析
在关系型数据库MySQL中,AUTO_INCREMENT是数据库的一个属性,该属性使得在申明了AUTO_INCREMENT的列中可以自动生成唯一的递增值。本文详细介绍了在InnoDB及MyISAM引擎中AUTO_INCREMENT的使用原理及一些容易被忽略的问题。
1106 0
|
自然语言处理 运维 开发工具
深入探讨了 NeoVim 相较于传统 Vim 的优势,包括更好的扩展性、现代化的界面和用户体验、多语言编程支持、强大的异步处理能力、更好的协作支持、持续的更新和改进、活跃的社区以及与现代开发工具的集成
本文深入探讨了 NeoVim 相较于传统 Vim 的优势,包括更好的扩展性、现代化的界面和用户体验、多语言编程支持、强大的异步处理能力、更好的协作支持、持续的更新和改进、活跃的社区以及与现代开发工具的集成。通过命令对比,展示了两者在启动、配置、模式切换、移动编辑、搜索替换、插件管理、文件操作、窗口缓冲区管理和高级功能等方面的差异。总结部分强调了 NeoVim 在多个方面的显著优势,解释了为什么越来越多的运维人员选择 NeoVim。
944 3
|
Java 编译器 Kotlin
Kotlin 中编写静态方法的方式详解
Kotlin 中编写静态方法的方式详解
615 0