天天看点

四大跨进程通信组件之AIDL(跨进程service通信)

AIDL:Android Interface Definition Language,即Android接口定义语言

为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程

  1. 百度百科

    过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案 一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。

  2. AIDL作为四大跨进程通讯手段之一,我们就算不能完全掌握它,也需要大概了解下它是如何运行的,下面我就写个小例子去展示它。

我会使用本进程AIDL的使用和跨进程AIDL的使用来讲解它

  1. 列表内容

    新建一个项目,在其中建立一个AIDL文件

interface AIDLTest {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */

     int add(int x,int y);
     int multiplication(int x , int y );

}
           

上面是定义的AIDL接口,里面有两个方法,一个加法一个乘法,我会在本进程实现加法,在外部进程实现乘法,然后log出来

5.创建一个server

private static final String TAG = "server";

    public void onCreate()
    {
        Log.e(TAG, "onCreate");
    }

    public IBinder onBind(Intent t)
    {
        Log.e(TAG, "onBind");
        return mBinder;
    }

    public void onDestroy()
    {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
    }

    public boolean onUnbind(Intent intent)
    {
        Log.e(TAG, "onUnbind");
        return super.onUnbind(intent);
    }

    public void onRebind(Intent intent)
    {
        Log.e(TAG, "onRebind");
        super.onRebind(intent);
    }

    private final AIDLTest.Stub mBinder = new AIDLTest.Stub()
    {

        @Override
        public int add(int x, int y) throws RemoteException
        {
            return x + y;
        }

        @Override
        public int multiplication(int x, int y) throws RemoteException {
            return ;
        }
           

注意看最后一段,在这里面实现接口里面定义的方法,然后再onBind中返回给activity,点击进Stub我们可以发现,他其实是一个继承Binder的抽象类

而Binder又是接口IBinder

所以AIDL和binder的关系其实是密不可分的,不过这里暂且不谈binder,我在这里,把乘法的返回值设为0,就是为了区分是本地进程,还是外部进程。

下面是mainactivity的代码

package com.example.myapplication;

import android.app.Activity;
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.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity implements ServiceConnection {
    private AIDLTest aidlTest;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
    /**
     * 点击BindService按钮时调用
     *
     * @param view
     */
    public void bindService(View view) {
        Intent intent = new Intent(MainActivity.this, MyService.class);
        bindService(intent, this, Context.BIND_AUTO_CREATE);
    }
    /**
     * 点击bindOtherServer按钮时调用
     *
     * @param view
     */
    public void bindOtherServer(View view) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.another","com.example.another.MyOtherServer"));
        bindService(intent,this,BIND_AUTO_CREATE);

    }

    /**
     * 点击2+3按钮时调用
     *
     * @param view
     */
    public void add(View view) throws Exception {

        if (aidlTest != null) {
            int addRes = aidlTest.add(, );
            Log.i("bindServer", "这是当前server加法的值为" + addRes);
            Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "重新绑定服务端", Toast.LENGTH_SHORT)
                    .show();

        }

    }

    /**
     * 点击2*3按钮时调用
     *
     * @param view
     */
    public void multiplication(View view) throws Exception {

        if (aidlTest != null) {
            int addRes = aidlTest.multiplication(, );
            Log.i("bindServer", "这是当前server乘法的值为0?" + addRes);
            Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "重新绑定服务端", Toast.LENGTH_SHORT)
                    .show();

        }

    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        aidlTest = AIDLTest.Stub.asInterface(service);
        if (aidlTest != null)
        {
            try {
                int addRes = aidlTest.multiplication(, );
                Log.i("bindServer", "这是外部server乘法的值为" + addRes);

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

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
}
           

这里代码量不多 我就干脆把xml也贴出来,免得给下载链接

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="bindService"
        android:text="绑定本地的服务" />


    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="bindOtherServer"
        android:text="绑定其他的服务" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="add"
        android:text="2+3" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="multiplication"
        android:text="2*3" />

</LinearLayout> 
           

上面其实就可以运行了 ,点击绑定本地的服务,点击下面两个计算按键可得

11-28 10:23:56.700 7654-7654/? I/bindServer: 这是当前server加法的值为5 11-28 10:23:57.900 7654-7654/? I/bindServer: 这是当前server乘法的值为0?0

下面在写一个另外一个项目:AIDLModeAnOther,这个的MainActivity和server比较简单

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);
        startService(new Intent(this,MyOtherServer.class));
    }
}
           

直接启动server即可,不过server中的方法和上面一致,就是这里改一下

private final AIDLTest.Stub mBinder = new AIDLTest.Stub()
    {

        @Override
        public int add(int x, int y) throws RemoteException
        {
            return x + y;
        }

        @Override
        public int multiplication(int x, int y) throws RemoteException {
            return x*y;
        }


    };
           

好知道这里能得出乘法的值。

然后再这个项目中也建立一个aidl包,重点来了,这两个项目的aidl要完全一样,从内容到包名。复制上面的下来即可

一切做完了之后,先点击下面这个AIDLModeAnOther运行,成了之后再 点击上面那个项目运行,点击绑定本地的服务,点击计算按键,显示本进程计算结果。再点击绑定其他的服务,就不用点击计算按键了,我图方便,直接就显示出来了 ,如下所示

- :: -/? I/bindServer: 这是当前server加法的值为
- :: -/? I/bindServer: 这是当前server乘法的值为?
- :: -/? I/bindServer: 这是外部server乘法的值为
           

到这里就算是演示完毕了 不过最后再说一个:从 Android 5.0 以后只能通信显式 Intent 来启动服务

开启服务用我上面所写的那样

Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.another","com.example.another.MyOtherServer"));
        bindService(intent,this,BIND_AUTO_CREATE);
           

而不能继续使用进程间通信 Intent机制 隐式启动了。

隐式启动就是在你的AndroidManifest,你要启动的服务或activity下加一个

<intent-filter>
                <action android:name="xxxxxxxxxx" />
           

然后在程序中

这样调用它

,好了这篇博客就将这么多,希望看过的人觉得好的留个言,点个赞,谢谢了!