Aidl实现的一个例子

AIDL 与 Messenger的异同

对于跨进程的调用

AIDL返回值是同步的,而Messenger是异步的。Aidl调用service的方法,会等待直到service中的方法执行完毕。

AIDL在Service中会针对每个请求开启新线程来执行客户端的调用。而Messenger会把消息放在主线程的队列里。

AIDL的实现,要注意线程安全的实现

oneway 关键字

修饰远程调用:

远程调用不会阻塞,它只是发送食物数据并立即返回

修饰本地进程:

不会有任何影响,调用仍是同步调用

AIDL支持的类型

  1. Java编程语言的原生基本类型 int、long、char、boolean
  2. String
  3. CharSequence
  4. List
    • List中的所有元素必须是上面支持的类型
    • 另一端实际接受的具体类型始终是ArrayList
  5. Map
    • Map中所有的元素都必须是上面支持的类型
    • 另一端实际接收的具体类始终是HashMap接口

必须为上面每个类加入import语句

一个AIDL的例子

Service端

1、编写AIDL的文件

// IAidlService.aidl
package com.jue.testservice1;
interface IAidlService {
    String getName(int num);
}

2、添加AndroidManifest文件

<service android:name=".AidlService" android:process=":AidlService" android:exported="true" android:enabled="true" >

    <intent-filter>
        <action android:name="com.jue.testservice1.IAidlService" />
    </intent-filter>
</service>
3、编写Service

public class AidlService extends Service {


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        logs("onBind  thread-" + Thread.currentThread().getName());
        return binder;
    }


    Binder binder = new IAidlService.Stub() {

        @Override
        public String getName(int num) throws RemoteException {

            logs("getName " + num + "  start  thread-" + Thread.currentThread().getName());

            String data = "nothing";

            try {
                Thread.sleep(1000);
            } catch (Exception e) {

            }


            if (num > 100) {
                data = " > 100, 百元";
            }

            if (num > 0) {
                data = "0-100以内";
            }

            logs("getName " + num + "  end  thread-" + Thread.currentThread().getName());

            return data;
        }
    };

    public static void logs(String text) {
        Log.i("jue","AidlService -> " + text);
    }

}

Client端

4、添加一样的AIDL文件

package com.jue.testservice1;

interface IAidlService {
    String getName(int num);
}

5、MainActivity的实现

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private int index;

    private IAidlService mIAidlService;

    private TextView mTitle;
    private View mBind;
    private View mUnbind;
    private View mGetData;

    private TextView mShowTitle;
    private View mShowBtn;

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

        mTitle = (TextView)findViewById(R.id.title);
        mBind = findViewById(R.id.bind);
        mUnbind = findViewById(R.id.unbind);
        mGetData = findViewById(R.id.get_data);

        mShowTitle = (TextView) findViewById(R.id.show);
        mShowBtn = findViewById(R.id.show_btn);

        mBind.setOnClickListener(this);
        mUnbind.setOnClickListener(this);
        mGetData.setOnClickListener(this);
        mShowBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        if (mBind == v) {
            Intent intent = new Intent();
            intent.setAction("com.jue.testservice1.IAidlService");
            intent.setPackage("com.jue.testservice1");
            bindService(intent, connection, BIND_AUTO_CREATE);
            return;
        }

        if (mUnbind == v) {
            unbindService(connection);
            return;
        }

        if (mGetData == v) {
            String data = "default";
            try {
                data = mIAidlService.getName(3002);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mTitle.setText(data);
        }

        if (mShowBtn == v) {
            mShowTitle.setText("" + index ++);
            return;
        }

    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            logs("onServiceConnected");

            mIAidlService = IAidlService.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            logs("onServiceDisconnected");
        }
    };

    public static void logs(String text) {
        Log.i("jue","MainActivity-> " + text);
    }

}

.aidl文件编译之后

package com.jue.testservice1;

public interface IAidlService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.jue.testservice1.IAidlService {
        private static final java.lang.String DESCRIPTOR = "com.jue.testservice1.IAidlService";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.jue.testservice1.IAidlService interface,
         * generating a proxy if needed.
         */
        public static com.jue.testservice1.IAidlService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.jue.testservice1.IAidlService))) {
                return ((com.jue.testservice1.IAidlService) iin);
            }
            return new com.jue.testservice1.IAidlService.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @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);
                    int _arg0;
                    _arg0 = data.readInt();
                    java.lang.String _result = this.getName(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.jue.testservice1.IAidlService {
            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;
            }

            @Override
            public java.lang.String getName(int num) 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);
                    _data.writeInt(num);
                    mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

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

    public java.lang.String getName(int num) throws android.os.RemoteException;
}

.aidl文件生成了同名的.java文件

生成的同名.java文件,继承了 android.os.IInterface接口

package android.os;

public interface IInterface
{

    public IBinder asBinder();
}

Stub类

  • 是一个抽象的内部类
  • Stub实现了IAidlService接口
  • Stub继承自android.os.Binder类 : 所以onBinder的时候,返回Stub对象就可以
  • Stub类有一个方法是asInterface,参数是IBinder,返回值是IAidlService接口。:在ServiceConnected时,client可以创建IAidlService接口的对象


Aidl Service端的代码开启了新线程用来执行来自Client端的代码


AIDL的一些细节

  • .aidl文件经过编译后会生成同名的.java文件。 如IRemoteService.aidl -> IRemoteService.java
  • 使用aidl的方式,需要在一开始就做好多线程的处理准备。
  • 如果明知服务完成请求的时间不止几毫秒,就不应该从Activity的主线程调用。通常需要从客户端的单独线程调用服务。
  • Service端引发的任何异常都不会传递给调用方







展开阅读全文

没有更多推荐了,返回首页