Android进阶之路——AIDL

一、AIDL
AIDL(Android Interface Definition Language)android接口定义语言,它可以用于让某个service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享一个service的功能。官方的文档是这样解释AIDL的:
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
第一句最重要,“只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”,其他情况你都可以选择其他方法,如使用messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的,而Messager是单线程处理。
二、AIDL的使用
首先需要创建一个AIDL文件,在这个文件中定义好Activity需要与Service进行通信的方法。首先看一下Demo工程的结构图
这里写图片描述

这里写图片描述
然后再来看看实现,首先定义AIDL接口,客户端和服务端都要定义,并且要在同一个包中。我在这个Demo中定义了两个接口文件,一个是服务端要实现的方法,如果这个方法是异步执行的,那么就需要回调,但是server是在另一个进程,我们怎么去调用呢?现在先不细说,这里的另一个接口就是用来回调的。

package com.test.server;
import com.test.server.ITaskCallback;
interface ITaskBinder {
       void registerCallback(ITaskCallback cb);
       void unregisterCallback(ITaskCallback cb);
}
package com.test.server;
interface ITaskCallback {
    void actionPerformed(int actionId);
}

编译后发现目录结构build/generated/source/aidl/debug/com.text.server/有相应的.java文件。
这里写图片描述
然后修改MyService中的代码,在其中实现我们刚刚定义的好的一个接口。

public class MyService extends Service {
    private static final String TAG = "tag";

    @Override
    public void onCreate() {
        printf("service create");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        printf("service start id=" + startId);
        callback(startId);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent t) {
        printf("service on bind");
        return mBinder;
    }

    @Override
    public void onDestroy() {
        printf("service on destroy");
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        printf("service on unbind");
        return super.onUnbind(intent);
    }

    public void onRebind(Intent intent) {
        printf("service on rebind");
        super.onRebind(intent);
    }

    private void printf(String str) {
        Log.v(TAG, "###################------ " + str + "------");
    }

    void callback(int val) {
        printf("val: " + val + "");
        final int N = mCallbacks.beginBroadcast();
        printf(N + "");
        for (int i = 0; i < N; i++) {
            try {
                mCallbacks.getBroadcastItem(i).actionPerformed(val);
            } catch (RemoteException e) {
            }
        }
        mCallbacks.finishBroadcast();
    }

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

        @Override
        public void registerCallback(ITaskCallback cb) throws RemoteException {
            if (cb != null) mCallbacks.register(cb);
        }

        @Override
        public void unregisterCallback(ITaskCallback cb) throws RemoteException {
            if (cb != null) mCallbacks.unregister(cb);
        }
    };

    final RemoteCallbackList<ITaskCallback> mCallbacks = new RemoteCallbackList<ITaskCallback>();

}

这样就完成了服务端的代码,大概解释一下代码,首先实现了一个接口的两个方法,在这个方法中可以实现一下逻辑(当然也可以新建一个线程去实现,这样可以更好的体现回调),然后在onBind()方法中将MyAIDLService.Stub的实现返回。这里为什么可以这样写呢?因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。在最后一行,可以看到系统提供的回调的类,系统也是通过广播来实现不同进程之间的消息通知。在onStartCommand()方法中调用了callback()方法,来通知其他进程。
然后看客户端的代码,客户端的代码仅实现一个activity的类。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "aidltest";
    private Button btnOk;
    private Button btnCancel, btnStart;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_main);

        btnOk = (Button) findViewById(R.id.btn_ok);
        btnCancel = (Button) findViewById(R.id.btn_cancel);
        btnStart = (Button) findViewById(R.id.start);
        btnCancel.setEnabled(false);


        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle args = new Bundle();
                Intent intent = new Intent("com.test.server.MyService");
                intent.putExtras(args);
                startService(intent);
//                bindService(intent, mConnection, BIND_AUTO_CREATE);
                btnCancel.setEnabled(true);
            }
        });
        btnOk.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                onOkClick();
            }
        });

        btnCancel.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                onCancelClick();
            }
        });
    }

    void onOkClick() {
        printf("send intent to start");
        Bundle args = new Bundle();
        Intent intent = new Intent("com.test.server.MyService");
        intent.putExtras(args);
//        startService(intent);
        bindService(intent, mConnection, BIND_AUTO_CREATE);
        btnCancel.setEnabled(true);
    }

    void onCancelClick() {

        printf("send intent to stop");
        //unbindService(mConnection);
        Intent intent = new Intent("com.cmcc.demo.IMyService");
        stopService(intent);
        btnCancel.setEnabled(false);
    }

    private void printf(String str) {
        Log.v(TAG, "###################------ " + str + "------");
    }

    ITaskBinder mService;

    private ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = ITaskBinder.Stub.asInterface(service);
            try {
                mService.registerCallback(mCallback);
                printf("stopRunningTask: " + mService.stopRunningTask() + "");
            } catch (RemoteException e) {

            }
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
        }
    };

    private ITaskCallback mCallback = new ITaskCallback.Stub() {

        public void actionPerformed(int id) {
            printf("callback id=" + id);
        }
    };

}

我们只是修改了ServiceConnection中的代码。可以看到,这里首先使用了MyAIDLService.Stub.asInterface()方法将传入的IBinder对象传换成了ITaskBinder对象,接下来就可以调用在ITaskBinder.aidl文件中定义的所有接口了。
这样这个Demo就完成了,运行程序,两个程序间就可以有数据的交互了。
三、AIDL小结
1、AIDL (Android Interface Definition Language )
2、AIDL 适用于 进程间通信,并且与Service端多个线程并发的情况,如果只是单个线程 可以使用 Messenger ,如果不需要IPC 可以使用Binder。
3、AIDL语法:基础数据类型都可以适用,List Map等有限适用。static field 不适用。
4、 客户端和服务端的AIDL接口文件所在的包必须相同
5、 需要一个Service类的配合

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值