Android Service AIDL的学习,传递对象

本文介绍了Android中AIDL(Android接口定义语言)的基础概念及其如何实现跨进程通信。通过实例详细展示了创建本地Service和远程Service的方法,并重点讲解了如何通过AIDL在远程Service中传递自定义对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android Service的学习,AIDL传递对象

Service有两种:
1,本地服务(Local Service):用于应用程序内部
2,远程服务(Remote Service):用于android系统内部的应用程序之间 。
使用区别:
本地服务:主要是平时做一些耗时,或者要长时间运行,影响UI线程的时候到到。如,播放音乐,下载等。
远程服务:则用于多应用之间的相互访问。比如做个天气预报的,做个健康数据的。

一开始我们学习使用Service可能会是因为播放多音乐的时候,用户启动了其他Activity这个时候程序要在后台继续播放。我们把MediaPlayer在Local Service里。然后通过bindService()在ServiceConnection里通过IBinder返回一个Service的实例。通过Service实例去操作MediaPlayer的开始和停止等等。例如这样:

Intent intent = new Intent(mContext, TestService.class);
mContext.bindService(intent, mServiceConnection, BIND_AUTO_CREATE);


private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mTestService = ((TestService.MyBinder) service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mTestService = null;
}
};

当某天用到远程Service的时候,上面这种方式报错了。
将一个普通的Service转换成远程Service其实非常简单,只需要在注册Service的时候将它的android:process属性指定成:remote就可以了。当然这个remote是自定义的。

为什么这里用个“:”呢?
如果被设置的进程名是以一个冒号开头的,则这个新的进程对于这个应用来说是私有的,当它被需要或者这个服务需要在新进程中运行的时候,这个新进程将会被创建。如果这个进程的名字是以小写字符开头的,则这个服务将运行在一个以这个名字命名的全局的进程中,当然前提是它有相应的权限。这将允许在不同应用中的各种组件可以共享一个进程,从而减少资源的占用。
当一个Service被设置为Remote Service时候我们又怎么通信呢?

我们再复习下线程通信与进程通信

线程通信:
- 1)共享变量(内存)
- 2)管道
- 3)handle机制 平时熟悉的runOnUiThread,view.post(Runnable)都是Handle机制
进程通信:
- 1)bind机制(IPC->AIDL)
- 2)Content Provider
- 3)Broadcast
- 4)Intent (有没试过用Intent打开别的应用。。)

这篇文章主要学习AIDL,AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。关于AIDL是怎么实现跨进程通信的,网上不少资料,关心的小伙伴可以自己查阅。强大的Android Studio为开发者省了很大的工夫。
第一步:创建AIDL:右键New-选择AIDL,输入你的接口名如IMyAidlInterface,点击Finish。
IDE会在src->main目录下新建一个aidl目录与java同级的。
第二步:自定义方法

interface IMyAidlInterface {
void addStudent(inout Student student);
void showTip(String tip);
}

第三步:Rebuild Project
在项目的 build/generated/source/aidl/debug/包名/下能找到IDE帮你生成的接口

第四步:在Service里返回一个IMyAidlInterface.Sub
“`
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
private class MyBinder extends IMyAidlInterface.Stub{
@Override
public void add(Student student) throws RemoteException {

    }
}

第五步:在BindService()
private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
        mIMyAidlInterface = null;
    }
};

“`
通过上边的五步我们就拿到了一个IMyAidlInterface实例。这时候可能欢呼了。

当你通过这个接口传一个对象过去的时候,崩了!!!!

查看资料发现AIDL默认支持的数据类型包括:
Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
String 类型。
CharSequence类型。
List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。

AIDL传送对象

由于Aidl只支持Java基本类型数据传递,因此是不能直接传递一个复杂类型对象的,所以为了解决这个问题,Android提供了一套机制—-将需要传递的对象序列化,然后在反序列化。
序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
第一步:创建一个Student类 implements Parcelable。按提示添加所有方法。(鼠标移动类名ALT+Enter–>add Parcelable implementation)

 public class Student implements Parcelable {
    int id;
    String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected Student(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

    public void readFromParcel(Parcel source) {
        id = source.readInt();
        name = source.readString();
    }


    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 "Student{" +
                "id=" + id +
                ", name=" + name +
                '}';
    }

}

第二步:在AIDL目录下里和你类放的路径一样的地方创建一个Student.AIDL

package com.example.yang.testaidl;
parcelable Student;   //parcelable 要小写,网上说的,我也不明真相。
  • 注意目录一定要相同
    例如,你在java/包名/beans/下创建的Student 你在aidl/包名/下再创建一个beans文件夹再这个beans下创建Student.aidl。要不然之前定义的IMyAidlInterface引用Student会报错。。。。

第三步:在IMyAidlInterface里加上
import com.example.yang.testaidl.Student;

interface IMyAidlInterface {
    void addStudent(inout Student student);
    void showTip(String  tip);
}

这里传对象用的是in/out/inout

Parcelable 还有这个方法是隐式的要自己写上来。这样就实现out了

public void readFromParcel(Parcel source) {
id = source.readInt();
name = source.readString();
}

好了。到了这里基本学习完毕。边学边写,有不足之处望批评指正。附Demo
https://github.com/YangKee/TestAIDL.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值