Android中的IPC方式AIDL

来源:互联网 发布:淘宝上通过网盘交易的 编辑:程序博客网 时间:2024/05/16 08:17

   IPC的全称是 inter-progress communication就是进程间通信,IPC不是Android独有的任何一个操作系统都需要IPC机制。当然了,我们只说Android,因为别的我也不会……。我们先说说AIDL的用处,只要就是跨进程通讯,例如我们打开的程序1想访问另外一个程序2中的某些方法或者数据时,就可能会用到AIDL,其实我们一般都用过AIDL只是你可能不知道,就像Android中的ContentProvider还有Messenger的底层其实都是AIDL实现的。


   用法:

   工程1:新建一个包,包里新建一个.aidl结尾的文件,.aidl文件的写法和接口类似,只是不能有修饰符,之后刷新工程,会在gen目录下系统自动生成一个包里面有个.java文件,然后把这个包连同里面的文件拷贝到工程2的gen目录下。

   工程2:把接收到的数据通过stub类的asInterface方法转换成需要的类型,然后就可以使用里面的方法了。


上面的说法感觉很抽象,接下来就举个栗子吧,这个栗子实现的功能就是同时开启两个程序,程序2可以获取程序1方法中的数据:

两个工程一个叫AIDL服务,一个叫AIDL客户端

AIDL服务的工程目录如下:




MainActivity.java里都是自动生成那些,我什么都没写。

Data.aidl的代码如下,这里的两个方法都是随便起的:

package com.zhangdi.aidl;

interface Data {
    String getName ();
    void setNumber(String num);
}


Myservice.java的代码如下:

package com.example.aidlservice;

import com.zhangdi.aidl.Data;

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

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return new Mybinder();
    }

    private class Mybinder extends Data.Stub {//继承AIDL中的stub类

        @Override
        public String getName() throws RemoteException {//实现.aidl文件中定义的方法
            // TODO Auto-generated method stub
            return "zhangsan";
        }

        @Override
        public void setNumber(String num) throws RemoteException {
            Log.i("zhangsan", "num = " + num);
        }
        
    }
}


Manifest文件配置如下:

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

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.example.aidlservice.MyService">
            <intent-filter>
                <action android:name="com.zhangdi.startService"/>
           </intent-filter>
        </service>

    </application>

</manifest>


AIDL客户端的工程目录如下:



com.zhangdi.aidl这个包是从AIDL服务里考过来的。

MainActivity.java里的代码如下:

package com.example.aidlclient;

import com.zhangdi.aidl.Data;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;


public class MainActivity extends Activity {

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

    public void startService(View v) {
        Intent intent = new Intent("com.zhangdi.startService");//启动服务的隐式意图
        conn = new ServiceConnection() {
            
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
            
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                try{
                    Data data = Data.Stub.asInterface(service);
                    Log.i("zhangdi", data.getName());//获取AIDL服务里getName方法中的数据
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
    
}

这个栗子很简单,接下来我们来分析一下系统自动生成的在gen目录下的com.zhangdi.aidl中的Data.java类。

我为了好看修改了一下文件的顺序,蓝色Data是最外面的接口,紫色是Data的内部类,黄色是紫色的内部类。Data类集成了IInterface接口,同时他自己也还是一个接口,所有可以在Binder中传输的接口都需要继承IInterface接口。首先Data类声明了两个方法,很显然这都是我们在Data.aidl中声明的方法,这也是为了后续实现Data接口类能够实现我们需要的方法,然后他在内部抽象类Stub中声明了两个常量用来区分两个方法,Stub同样没有实现我们需要的两个方法,显然这个两个方法需要由Stub的继承类来实现,asInterface方法判断了传递进来的IBinder对象是是在同一个进程中还是不同进程,相同进程则返回Stub类本身对象,不调用transact方法保存可以跨进程传递的信息,只有在不同进程返回的是Stub.Proxy对象,才调用transact方法,调用transact方法的逻辑由Stub的内部类Proxy来完成。


/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\workspace6\\AIDL服务\\src\\com\\zhangdi\\aidl\\Data.aidl
 */
package com.zhangdi.aidl;
public interface Data extends android.os.IInterface
{

    public java.lang.String getName() throws android.os.RemoteException;
    public void setNumber(java.lang.String num) throws android.os.RemoteException;


    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.zhangdi.aidl.Data
    {

       //Binder的唯一标示

        private static final java.lang.String DESCRIPTOR = "com.zhangdi.aidl.Data";

        static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setNumber = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);


        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.zhangdi.aidl.Data interface,
         * generating a proxy if needed.
         */

       //asInterface方法是把相同进程中的IBinder对象强转为Data类型接口对象的方法,如果在不同进程则产生一个proxy类型的对象

        public static com.zhangdi.aidl.Data asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.zhangdi.aidl.Data))) {
                return ((com.zhangdi.aidl.Data)iin);
            }
            return new com.zhangdi.aidl.Data.Stub.Proxy(obj);
        }
        @Override public android.os.IBinder asBinder()
        {
            return this;
        }


//这个方法是运行在服务端的Binder线程池中,当客户端发起跨进程访问请求时,远程请求会通过系统底层封装后交由这个方法来处理。这个方法的原型是protected boolean onTransact(int code, Parcel data, Parcel reply,
            int flags),服务端通过code可以确定客户端请求的目标是哪个方法,接着从data中取出方法所需参数,然后执行目标方法,最后通过reply写入返回值,最后需要注意的是如果最后方法返回的boolean值是false,则客户端请求失败,因此我们可以通过这个特性做权限校验,毕竟我们不希望任何进程都可以远程调用我们的进程。

        @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code)
            {
            case INTERFACE_TRANSACTION:
            {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getName:
            {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _result = this.getName();
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            case TRANSACTION_setNumber:
            {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                this.setNumber(_arg0);
                reply.writeNoException();
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }


        private static class Proxy implements com.zhangdi.aidl.Data
        {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }
            @Override public android.os.IBinder asBinder()
            {
                return mRemote;
            }
            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }


//这个方法是运行在客户端的,实现过程:首先创建该方法需要的Parcel类型的输入对象_data和输出对象_reply以及返回值对象_result,如果该方法有参数则把参数写入_data中,接着调用transact方法来发起远程过程调用请求,同时当前线程挂起,在transact方法中会调用服务器端的OnTransact方法,直至远程过程调用返回结果,当前线程才继续执行,从_reply中取出结果,最后返回_reply中的数据。

            @Override public java.lang.String getName() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }


//这个方法与上边的方法实现原理基本一样。

            @Override public void setNumber(java.lang.String num) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(num);
                    mRemote.transact(Stub.TRANSACTION_setNumber, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

      
    }
   
}



0 0
原创粉丝点击