AIDL 进程间通信的一个小小的总结

 

需求

  项目需要,将做好的项目作为一个服务提供给另一个公司。我们需要提供一个apk,所以设计到进程间交互,不得不了解一下AIDL了。

 

 

了解一下AIDL

  之前准备面试的时候,或多或少的了解了一点AIDL,不过现在忘记得差不多了。

  所以网上随便找了几篇不错的文章。

  1.进程通信之AIDL的使用。

  2.学习AIDL,这一篇就够了。

 

 

一个简单的demo

  自己搞了一个简单的demo。

  实现了进程间通信,可以传输普通类型和实体类型。

  首先是服务端。

  1.第一个aidl接口。

// IMyAidlInterface.aidl
package com.xf.test1;

import com.xf.test1.IAidlCallBack;
import com.xf.test1.Entity;
// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);


    String getStr(String str);

    int getPid();

    Entity getEntity();

    Entity setEntity(in Entity entity);

    void registerCallBack(IAidlCallBack callback);

    void unregisterCallBack(IAidlCallBack callback);
}
View Code

  2.第二个aidl接口。

// IAidlCallBack.aidl
package com.xf.test1;

import com.xf.test1.Entity;

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

interface IAidlCallBack {

    void callBack(String name);

    void callBackEntity(in Entity entity);
}
View Code

  3.第三个aidl接口。

// Person.aidl
package com.xf.test1;

parcelable Entity;
View Code

  4.封装的一个IBinder。

package com.xf.test1;

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

public class AIDLService extends Service {


    private AIDLImp mBinder;


    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new AIDLImp(this);
    }

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


    @Override
    public void onDestroy() {
        super.onDestroy();
        mBinder.KillAll();
    }
}
View Code

  5.AIDL服务。

package com.xf.test1;

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

public class AIDLService extends Service {


    private AIDLImp mBinder;


    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new AIDLImp(this);
    }

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


    @Override
    public void onDestroy() {
        super.onDestroy();
        mBinder.KillAll();
    }
}
View Code

  6.实体类型。

package com.xf.test1;

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

/**
 * Description: 简单实体类
 *
 * @version V1.0.0
 * Createdate: 2018/6/22
 * @author: wja 1211241203@qq.com
 */
public class Entity implements Parcelable {

    private String name;

    private int parameter1;

    private double parameter2;

    public Entity(String name){
        this.name=name;
    }

    public Entity(String name, int parameter1, double parameter2) {
        this.name = name;
        this.parameter1 = parameter1;
        this.parameter2 = parameter2;
    }

    public int getParameter1() {
        return parameter1;
    }

    public void setParameter1(int parameter1) {
        this.parameter1 = parameter1;
    }

    public double getParameter2() {
        return parameter2;
    }

    public void setParameter2(double parameter2) {
        this.parameter2 = parameter2;
    }

    public String getName() {
        return name;
    }

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

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

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

    protected Entity(Parcel in) {
        this.name = in.readString();
        this.parameter1 = in.readInt();
        this.parameter2 = in.readDouble();
    }

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

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

    @Override
    public String toString() {
        return "Entity{" +
                "name='" + name + '\'' +
                ", parameter1=" + parameter1 +
                ", parameter2=" + parameter2 +
                '}';
    }
}
View Code

  7.清单文件。

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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" />

                <data android:scheme="com.xf.aidl.test" />
            </intent-filter>-->
        </activity>


        <service android:name=".AIDLService">
            <intent-filter>
                <action android:name="com.xf.aidl" />
                <category android:name="android.intent.category.DEFAULT" />
                <!--<action android:name="android.intent.action.MAIN" />-->

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

</manifest>
View Code

  8.服务端如何运行(不使用启动图标的方式)

   

  然后点击进去

  

  9.最后点击运行,服务就安装在手机啦。

  

  其次,是客户端。

  1.客户端的aidl文件和服务端的完全一样。(当然路径可以不一样,为了方便我直接copy的,路径不一样也是可以的,测试过的)

  2.然后注意实体类型所在的包一定要和服务端的一致,负责找不到这个实体的。

  3.最后是客户端的主页面。

package com.xf.test2;

import android.content.ComponentName;
import android.content.Context;
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.AppCompatActivity;
import android.util.Log;
import android.view.View;

import com.xf.test1.Entity;
import com.xf.test1.IAidlCallBack;
import com.xf.test1.IMyAidlInterface;

import java.util.Random;

public class MainActivity extends AppCompatActivity {

    private IMyAidlInterface mIMyAidlInterfaceService;


    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mIMyAidlInterfaceService = IMyAidlInterface.Stub.asInterface(service);
            try {
                mIMyAidlInterfaceService.registerCallBack(mIAidlCallBack);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            try {
                mIMyAidlInterfaceService.unregisterCallBack(mIAidlCallBack);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mIMyAidlInterfaceService = null;
        }
    };


    private IAidlCallBack mIAidlCallBack = new IAidlCallBack.Stub() {
        @Override
        public void callBack(String name) throws RemoteException {
            Log.e("info---->","服务端给我发消息啦:"+name);
            ToastUtil.showShort(MainActivity.this,"服务端给我发消息啦:"+name);
        }

        @Override
        public void callBackEntity(Entity entity) {
            Log.e("info---->","服务端给我发实体消息啦:"+entity.toString());
            ToastUtil.showShort(MainActivity.this,"服务端给我发实体消息啦:"+entity.toString());
        }
    };


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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mServiceConnection != null)
            unbindService(mServiceConnection);
    }

    /**
     * 绑定服务
     * @param view
     */
    public void doClick(View view) {
        Intent intent = new Intent();
        intent.setAction("com.xf.aidl");
        intent.setPackage("com.xf.test1");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }


    /**
     * 获取服务器发送过来的消息
     * @param v
     */
    public void doAction(View v) {
        if (mIMyAidlInterfaceService != null) {
            try {
                String newstr = mIMyAidlInterfaceService.getStr("Hello world");
                int pid = mIMyAidlInterfaceService.getPid();
                Log.e("info---->", newstr + " pid:" + pid);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 客户端自己设置实体,发送给服务端
     * 通过随机数设置实体参数
     * @param v
     */
    public void doActionSetEntity(View v){
        if (mIMyAidlInterfaceService != null) {
            try {
               Random random=new Random();
               mIMyAidlInterfaceService.setEntity(new Entity("客户端",random.nextInt(100),random.nextDouble()));

            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

    下面是布局文件。

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

    <RelativeLayout
        android:layout_marginTop="100dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:onClick="doClick"
            android:text="绑定服务"
            android:layout_centerInParent="true"
             />

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:onClick="doAction"
            android:text="获取消息"
            android:layout_centerInParent="true"
            />

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:onClick="doActionSetEntity"
            android:text="客户端设置实体"
            android:layout_centerInParent="true"
            />

    </RelativeLayout>

</LinearLayout>
View Code

  

  运行效果是这样的:

        

 

   这里客户端首先需要绑定服务

  点击了获取消息:直接获取服务端创建好的实体类。

  点击了客户端设置实体:通过产生随机数,客户端调用aidl接口设置实体。

  如果再次点击获取消息:在服务端进行判断,如果客户端设置过实体,就把该实体发送回客户端。

 

  demo地址:https://github.com/JasonToJan/AIDLDemo

 

 

个人小结

  1.首先要理解aidl是干什么的:进程间交互。不同apk实现通信。

  2.为什么可以做到进程间通信了,谁给两个进程之间搭起了一座桥梁呢?AIDL,其实就是一个接口,实现进程之间对接的功能。

  3.两个进程要做到通信,aidl一定要保证一致,不然就是牛头不对马嘴了。

  4.aidl如何实现数据传输了,binder。所以demo就把binder直接封装起来,基本所有逻辑都在这个封装类中进行即可。

  5.再深入底层,binder是如何实现数据传输的呢?这就涉及到操作系统的知识了,binder处于一个内存共享区域,可以实现进程间通信。

 

posted @ 2018-06-22 17:35  Jason_Jan  阅读(739)  评论(0编辑  收藏  举报