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

来源:互联网 发布:python 分布式计算 编辑:程序博客网 时间:2024/06/05 18:22

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 0;        }

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

public static abstract class Stub extends android.os.Binder implements com.example.myapplication.AIDLTest

而Binder又是接口IBinder

public class Binder implements 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(2, 3);            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(2, 3);            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(58, 12);                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运行,成了之后再 点击上面那个项目运行,点击绑定本地的服务,点击计算按键,显示本进程计算结果。再点击绑定其他的服务,就不用点击计算按键了,我图方便,直接就显示出来了 ,如下所示

11-28 10:32:41.650 7921-7921/? I/bindServer: 这是当前server加法的值为511-28 10:32:42.070 7921-7921/? I/bindServer: 这是当前server乘法的值为0011-28 10:32:43.410 7921-7921/? I/bindServer: 这是外部server乘法的值为6

到这里就算是演示完毕了 不过最后再说一个:从 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" />

然后在程序中

Intent intent = new Intent("xxxxxxxx"); //这个为隐式启动Activity的搜索名称

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

1 0