androidstudio中AIDL的使用详解

AIDL在项目中用的真的很少,所以每次学完,过段时间关于使用aidl的步骤就会忘记,所以用笔记记录下来,避免每次都要百度。

首先建立一个AIDLProject工程。
工程中建立两个module分别为aidlclient(客户端)、aidlserver(服务端)。

这里写图片描述

先写服务端

aidl支持传递的数据类型:

  1. Java 的原生类型

6种数字类型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)、float(4字节)、double(8字节)

1种字符类型:char(2字节)

1种布尔类型:boolean(1字节)

  1. String 和CharSequence

  2. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;  以上三种类型都不需要导入(import)

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

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

1、基本类型的aidl传递

在aidlserver中新建aidl的folder文件夹

这里写图片描述

aidl文件夹和java、res处于同级:

这里写图片描述

新建IConnect.aidl文件

这里写图片描述

// IConnect.aidl

package com.aidl.server;



// Declare any non-default types here with import statements



interface IConnect {

   String connect();



}

新建IConnect.aidl文件,然后紧接着执行Build->Make Project,编译该aidl文件

这里写图片描述

在java文件夹中包下新建ConnectService继承Service

package com.aidl.server;



import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;



public class ConnectService extends Service {

    public ConnectService() {

    }



    @Override

    public IBinder onBind(Intent intent) {

        // TODO: Return the communication channel to the service.

        return new MyBinder();

    }



    class MyBinder extends IConnect.Stub

    {



        @Override

        public String connect() throws RemoteException {

            rethrows RemoteException {

            return "connect success";

        }

    }


}

在清单文件中配置ConnectService的Action

<service

            android:name=".ConnectService"

            android:enabled="true"

            android:exported="true">

            <intent-filter>

                <action android:name="com.aidl.server.connect" />

            </intent-filter>

        </service>

至此服务端的就完成了。

客户端aidlclient

把服务端aidlserver中的aidl文件夹复制到客户端aidlclient中。同样编译Build->Make Project。

在MainActivity中连接服务端

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <Button
        android:layout_width="150dp"
        android:layout_height="50dp"
        android:text="connect测试"
        android:layout_gravity="center"
        android:onClick="test"
        />
</LinearLayout>

MainActivity.java代码
在android5.0之后谷歌默认不允许隐式启动Service,有两种方法可以解决
1、createExplicitFromImplicitIntent用这个方法处理Intent
2、设置包名intent.setPackage(“com.aidl.server”);

public class MainActivity extends AppCompatActivity {
    private IConnect iConnect;
    Intent connect;
    Intent connect1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        aidlconnect();
    }

    private void aidlconnect() {
        connect1 = new Intent();
        connect1.setAction("com.aidl.server.connect");
        //intent.setPackage("com.aidl.server");
        connect = new Intent(createExplicitFromImplicitIntent(this,connect1)) ;
        bindService(connect,conn,BIND_AUTO_CREATE);
    }

    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            iConnect = IConnect.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }

客户端也写好了,接下来就是测试

先运行服务端aidlserver,再运行客户端aidlclient

这里写图片描述

至此基本类型的aidl数据传递完成了。

2、自定义类型的aidl传递

同样先写服务端aidlserver

在java中新建一个自定义类型如User.java

这里写图片描述

package com.aidl.server;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Tony on 2017/6/10.
 */

public class User implements Parcelable{

    private String name;
    private String age;

    public User(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "name "+name+" age "+age;
    }

    protected User(Parcel in) {
        name = in.readString();
        age = in.readString();
    }

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

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeStrin自定义数据类型完成后,需要在aidl文件夹中新建一个和自定义数据类型同名的aidl文件这里需要User.aidl,用来指定User类的me);
        parcel.writeString(age);
    }
}

这个User必须序列化,aidl传递的数据类型包括(实现android.os.Parcelable 接口的类.  需要导入(import)。)

自定义数据类型完成后,需要在aidl文件夹中新建一个和自定义数据类型同名的aidl文件这里需要User.aidl,用来指定User类的位置,User用小写的parcelable修饰。

package com.aidl.server;
parcelable User;

再定义一个用来操作User类的aidl接口,IUser.aidl

这里需要import这个User类

如果方法参数的类型不是原生类型,如String,List或自定义实体类,需要使用in、 out或 inout 修饰,in表示这个值被客户端设置; out  表示这个值被服务端设置,inout 表示这个值既被客户端设置,又被服务端设置.

// IUser.aidl
package com.aidl.server;
import com.aidl.server.User;
// Declare any non-default types here with import statements

interface IUser {

    String getName();
    User getUser(in String name,in String age);

}

然后同样Build->Make Project编译IUser.aidl文件

新建UserService继承Service,实现IUser.Stub

package com.aidl.server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class UserService extends Service {
    public UserService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new MyBinder();
    }

    class MyBinder extends IUser.Stub {

        @Override
        public String getName() throws RemoteException {
            return "tony";
        }

        @Override
        public User getUser(String name, String age) throws RemoteException {
            return new User(name,age);
        }
    }
}

在清单文件中配置UserService

<service
            android:name=".UserService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.aidl.server.user" />
            </intent-filter>
        </service>

自此自定义数据aidl服务端就完成了。

自定义数据传递aidl客户端

需要将服务端的User.java、IUser.aidl、User.aidl三个文件拷贝到客户端的aidl文件夹中,然后Build->Make Project,编译,这个时候会出错找不到User.java类,因为User在aidl文件夹下,所以要在build.gradle配置sourceSets

sourceSets {
        main{
            java.srcDirs=['src/main/java','src/main/aidl']
        }
    }

再次Build->Make Project就可以了。

再客户端aidlclient中连接服务端aidlserver

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <Button
        android:layout_width="150dp"
        android:layout_height="50dp"
        android:text="获取user对象测试"
        android:layout_gravity="center"
        android:onClick="loaduser"
        />

</LinearLayout>

MainActivity.java

package com.aidl.client;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.aidl.server.IConnect;
import com.aidl.server.IUser;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private IUser iUser;
    Intent userintent;
    Intent userintent1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       aidluser();
    }

    private void aidluser() {
        userintent1 = new Intent();
        userintent1.setAction("com.aidl.server.user");
        //intent.setPackage("com.aidl.server");
        userintent = new Intent(createExplicitFromImplicitIntent(this,userintent1));
        bindService(userintent,connuser,BIND_AUTO_CREATE);
    }

    public void loaduser(View v){
        try {
             //客户端传参数
            Toast.makeText(this,iUser.getUser("tony","20").toString(),Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    ServiceConnection connuser = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            iUser = IUser.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such unbindService(connuser);
reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();


        unbindService(connuser);
    }

}

接下来就是测试了
先运行服务端,再运行客户端测试如下:

这里写图片描述

自此自定义数据类型的aidl的传递就结束了。

源码地址:

https://github.com/fsdsds/AIDLProject/tree/master

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值