一块儿简单写一下AIDL,入个门

前话

最近接触了Android开发的一个新知识,AIDL(¬_¬由于到如今都没用过)
所以不断谷歌找资料找Demo,本身尝试写一下。
由于用AndroidStudio做为开发环境,期间遇到过许多问题,所以写下来看成笔记,也给新接触这个知识点的同窗们一个小指引。html

这里推荐两篇文章:java

Android:学习AIDL,这一篇文章就够了(上)android

Android:学习AIDL,这一篇文章就够了(下)markdown


什么是AIDL

什么是AIDL?这个谷歌一下有不少,我就摘抄一段 ↓多线程

对于AIDL有一些人的浅显概念就是,AIDL能够跨进程访问其余应用程序,和其余应用程序通信。并发

那我告诉你,不少技术均可以访问。app

如广播(应用A在AndroidManifest.xml中注册指定Action的广播)应用B发送指定Action的广播,A就能收到信息,这样也能当作不一样应用之间完成了通信(可是这种通信是单向的);
还如ContentProvider,经过URI接口暴露数据给其余应用访问;less

可是这种都算不上是应用之间的通信。可能最让人迷惑的是Android推出来了Messager,它就是完成应用之间的通信的。ide

那么为何还要有AIDL呢,官方文档介绍AIDL中有这么一句话:学习

Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.

第一句最重要,“只有当你容许来自不一样的客户端访问你的服务而且须要处理多线程问题时你才必须使用AIDL”,其余状况下你均可以选择其余方法,如使用Messager,也能跨进程通信。

可见AIDL是处理多线程、多客户端并发访问的。

而Messager是单线程处理。仍是官方文档说的明白,一句话就能够理解为何要有AIDL。

看到这里你们应该也简单知道什么是AIDL了,下面咱们简单动手写一下AIDL,能够加深理解。


一块儿写AIDL

这次使用AIDL,咱们就用来在两个不一样进程间传输复杂数据吧。

首先咱们定义一下需求,咱们想实现这样的功能,就是一个服务端启动一个Service,这个Service用来接收客户端传来的数据,并将该数据打印出来。

客户端 –> 客户端传递数据(例如User类对象) –> 服务端 –>服务端打印接收到的数据

结合这样的功能需求,咱们须要建立两个APP。

  • 一个APP做为服务端用来启动Service接收并打印数据
  • 一个APP做为客户端用来绑定服务端的Service并传递数据给该Service

服务端

最终项目结构

01


源码

User.aidl 和 User.java

由于要传递复杂数据,这里用User做为例子,所以咱们要定义User的AIDL文件。

由于开发环境是AndroidStudio,因此咱们要先在aidl文件夹内建立 User.aidl

User.aidl

package me.pwcong.aidlservice.model;

parcelable User;

而后咱们再在java文件夹内建立User.java。
由于User做为复杂数据,在不一样进程之间传递须要序列化,所以它须要继承Parcelable。
这里源码省略get、set和toString方法。

User.java

package me.pwcong.aidlservice.model;

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

public class User implements Parcelable {

    String name;
    int age;
    String gender;

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

    public void readFromParcel(Parcel dest){
        this.name=dest.readString();
        this.age=dest.readInt();
        this.gender=dest.readString();
    }

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

    public User() {
    }

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

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

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

特别注意,User.aidl 和 User.java 和包名和路径必需要同样
例如上面User.aidl和User.java的包路径均为 package me.pwcong.aidlservice.model;


MainInterface.aidl

接着咱们定义一个接口AIDL文件,用做不一样进程间传递数据。

MainInterface.aidl

package me.pwcong.aidlservice;

//引用其余类文件是否在同一包内都须要import
import me.pwcong.aidlservice.model.User;

interface MainInterface {

    //注意这里的前缀in,表示数据流只能由客户端传到服务端    
    void introduce(in User user);
}

到这里咱们就写好了服务端的AIDL,咱们将该项目make一下,若是没有报错,则说明AIDL成功的编译导出了相关的java类文件,在generate文件夹内能够找到。


MainActivity和MainService

MainService.java

package me.pwcong.aidlservice.component.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import me.pwcong.aidlservice.MainInterface;
import me.pwcong.aidlservice.model.User;

public class MainService extends Service {

    private final String TAG=getClass().getSimpleName();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mainInterface;
    }

    private final MainInterface.Stub mainInterface=new MainInterface.Stub() {
        @Override
        public void introduce(User user) throws RemoteException {
            Log.i(TAG, "introduce: "+ user.toString());
        }
    };


}

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import me.pwcong.aidlservice.R;

public class MainActivity extends AppCompatActivity {

    private final String TAG=getClass().getSimpleName();

    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: OK");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: OK");
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent=new Intent();
        intent.setAction("me.pwcong.aidlservice.aidl");
        startService(intent);

        bindService(intent,serviceConnection,BIND_AUTO_CREATE);

    }
}

最后在AndroidManifest.xml内进行Service的配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.pwcong.aidlservice">

    <application  android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".component.activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".component.service.MainService">

            <intent-filter>

                <action android:name="me.pwcong.aidlservice.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>

            </intent-filter>

        </service>


    </application>

</manifest>

启动服务端

咱们点击运行,若logcat中输出以下这句说明服务端Service启动成功

09-13 02:44:36.888 1413-1413/? I/MainActivity: onServiceConnected: OK

客户端

最终文件结构

02


源码

User.java,User.aidl 和 MainInterface.aidl

由于客户端须要传递数据给服务端,所以它的AIDL文件必须和服务端的同样,因此咱们将服务端的User.java,User.aidl 和 MainInterface.aidl 拷贝至相应目录。

特别注意,这三个文件的包名路径务必和服务端一致,如上图最终文件结构所示

接着咱们再make一下项目,若是没有报错,咱们就能够进行下一步了


MainActivity.java 和 AndroidManifest.xml

MainActivity.java

package me.pwcong.aidlclient;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import me.pwcong.aidlservice.MainInterface;
import me.pwcong.aidlservice.model.User;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private final String TAG=getClass().getSimpleName();

    Button button;

    MainInterface mainInterface;

    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //将绑定的service转成所定义的AIDL接口类
            mainInterface= MainInterface.Stub.asInterface(service);

            Log.i(TAG, "onServiceConnected: "+name);
            Log.i(TAG, "onServiceConnected: OK");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: "+name);
            Log.i(TAG, "onServiceDisconnected: OK");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent=new Intent();

        //特别注意这里设置了服务端APP的包名
        intent.setPackage("me.pwcong.aidlservice");
        //这里设置action为服务端APP对Service所定义的action值
        intent.setAction("me.pwcong.aidlservice.aidl");

        bindService(intent,serviceConnection,BIND_AUTO_CREATE);

        button= (Button) findViewById(R.id.btn);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        if(mainInterface!=null){

            User user=new User();
            user.setName("Pwcong");
            user.setAge(20);
            user.setGender("Man");

            try {
                mainInterface.introduce(user);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

    }
}

这个Activity里面简单实现了绑定服务端的Service,和经过点击按钮给服务端Service发送User类对象数据。

AndroidMainifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.pwcong.aidlclient">

    <application  android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

启动客户端

咱们运行客户端,若输出以下说明客户端绑定服务端Service成功:

09-13 03:05:17.552 20379-20379/me.pwcong.aidlclient I/MainActivity: onServiceConnected: OK

接着咱们点击按钮,若输出以下说明AIDL传输数据成功:

09-13 03:08:01.520 1413-1426/me.pwcong.aidlservice I/MainService: introduce: User{name='Pwcong', age=20, gender='Man'}

结束

到这里咱们简单的AIDL入门就写完了。

若是这次入门项目书写事后仍懵懂的话我仍是推荐你们认真阅读前面所推荐的两篇入门文章吧。

毕竟我也是刚入门哈。

相关文章
相关标签/搜索