android AIDL基础

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android AIDL基础相关的知识,希望对你有一定的参考价值。

android的每一个应用都是运行在单独的一个进程里。进程间的通信主要有以下四种:

1> Activity:可以结合Intent使用,启动其他进程的活动;

2> 广播:广播为跨进程间的通信;

3> ContentProvide:内容提供者,以Cursor对象访问其他进程数据或者为其他进程提供数据;

3> Service:主要通过AIDl实现进程间通信;

 

AIDL全程为安卓接口定义语言。

具体参考: http://blog.csdn.net/luoyanglizi/article/details/51980630

下面通过在Androidstudio上实现Client向服务端提交数据的实例对AIDL进行学习。

Client:

1> 我们都知道,每一个进程都有自己的独立内存。如果需要在进程间传递对象,则需将对象序列化。

     #java语言

     创建类,直接实现Serializable接口

     #Android独有,实现Parcelable接口

创建Persion类,实现Parcelable接口

package com.example.aidltest;

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

/**
 * Created by 阿正 on 2017/4/10 0010.
 */

public class Persion implements Parcelable {
    public String name;
    public int age;

    public Persion() {
    }

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

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

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

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

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

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Persion{" +
                "name=‘" + name + ‘\\‘‘ +
                ", age=" + age +
                ‘}‘;
    }
}

2> 创建AIDL

对应文件位置:

技术分享

Persion.aidl

// Persion.aidl
package com.example.aidltest;

// Declare any non-default types here with import statements
parcelable Persion;

PersionManager.aidl

// IPersionManager.aidl
package com.example.aidltest;

// Declare any non-default types here with import statements
// 这里引入的是Persion.aidl
import com.example.aidltest.Persion;

interface IPersionManager {
    // 定义方法,所有的返回值前不需要修饰关键字;如果非默认类型,需要在参数前添加 in/out/inout
    // in 客户端向服务端提供数据;out 客户端向服务端获取数据
    List<Persion> getPersion();
    void addPersion(in Persion ipersion);
}

到这里,创建结构类并序列化,创建AIDL已经完成。需要注意的是在创建Persion.aidl的时候,名字尽量和Persion.java一致。比如我之前创建IPersion.aidl时,clean项目的时候就报错。

客户端:客户端主要实现启动/停止service

package com.example.aidltest;

import android.content.ComponentName;
import android.content.Context;
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 android.widget.EditText;

import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button mAdd;
    private Button mConnect;
    private EditText mTextName;
    private EditText mTextAge;

    //是否连接服务端
    private boolean isconnect = false;

    private IPersionManager mPersionManager;
    private List<Persion> mPersions;
    public MainActivity() {
    }

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

        mTextName = (EditText) findViewById(R.id.text_name) ;
        mTextAge = (EditText) findViewById(R.id.text_age);
        mAdd = (Button) findViewById(R.id.add);
        mConnect = (Button)findViewById(R.id.connect);
        mAdd.setOnClickListener(this);
        mConnect.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.add:
                // 调用服务端实现的方法,对数据进行改动
                addBook();
                break;
            case R.id.connect:
                // 启动service并绑定
                Intent intent = new Intent();
                intent.setAction("azheng");
                intent.setPackage("com.example.aidltestservice");
                bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
                break;
        }
    }

    private void addBook(){
        if (!isconnect){
            Log.d("azheng" ,"clent: Not connected,please connect to service first!");
            return;
        }
        if (mPersionManager == null){return;}
        Persion persion = new Persion();
        String name = mTextName.getText().toString();
        persion.setName(name);
        int age = Integer.parseInt(mTextAge.getText().toString());
        persion.setAge(age);
        try {
            mPersionManager.addPersion(persion);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    // 创建ServiceConnection,与服务端连接
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("azheng" ,"clent: connected");
            // 获得服务端的IPersionManager
            mPersionManager = IPersionManager.Stub.asInterface(service);
            isconnect = true;
            try {
                Log.d("azheng" ,"clent: before add:" + mPersionManager.getPersion().toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("azheng" ,"clent: connected");
            isconnect = false;
        }
    };

    @Override
    protected void onStop() {
        super.onStop();
        if (isconnect){
            unbindService(serviceConnection);
        }
    }
}

 

服务端:

服务端的Persion.java Persion.aidl IPersionManager.aidl三个文件的包名,内容需要与client一致。因此最好的办法是直接从client复制过来。

技术分享

 

Persion.java

// 这里的包名需要与服务端一致
package com.example.aidltest;

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

/**
 * Created by 阿正 on 2017/4/10 0010.
 */

public class Persion implements Parcelable {
    public String name;
    public int age;

    public Persion() {
    }

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

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

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

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

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

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Persion{" +
                "name=‘" + name + ‘\\‘‘ +
                ", age=" + age +
                ‘}‘;
    }
}

具体的服务类AIDLService

package com.example.aidltestservice;

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 com.example.aidltest.IPersionManager;
import com.example.aidltest.Persion;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by 阿正 on 2017/4/10 0010.
 */

public class AIDLService extends Service {
    private List<Persion> mPersions = new ArrayList<>();

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

    // 实现IPersionManager。aidl
    private final IPersionManager.Stub persionManager = new IPersionManager.Stub(){

        @Override
        public List<Persion> getPersion() throws RemoteException {
            synchronized (this){
                if (mPersions != null){
                    return mPersions;
                }
            }
            return null;
        }

        @Override
        public void addPersion(Persion ipersion) throws RemoteException {
            synchronized (this){
                if (ipersion == null){
                    Log.d("azheng","service: persion from clent is null!");
                }else {
                    mPersions.add(ipersion);
                }
                Log.d("azheng","service: result" + mPersions.toString());
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("azheng" ,"service: onCreate()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("azheng" ,"service: onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("azheng" ,"service: onDestroy()");
    }
}

ok,到这里就完成了。

补充一点:上面提到客户端和服务端的{Persion.java Persion.aidl IPersionManager.aidl}需要一致,为了方便复制,这里提供另一种方法。

1> 将Persion.java 文件拷贝到aidl文件夹中

     技术分享

2> 上面的操作会导致Persion.java文件编译器找不到,因为AndroidStudio是通过sourceSets来配置不同文件的访问路径的。

     修改 build.gradle 文件:在 android{} 中间加上下面的内容:

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

 

以上是关于android AIDL基础的主要内容,如果未能解决你的问题,请参考以下文章

Android——AIDL基础实现demo以及原理探究

android AIDL基础

Android Service aidl使用及进阶

Android Service aidl分析

Android基础——Binder连接池连接多个AIDL文件的处理

Android AIDL 小结