Android开发——进程间通信之AIDL(一)

0.  前言

不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPCInter-Process Communication)即进程间通信。首先线程和进程是很不同的概念,线程是CPU调用的最小单元,进程一般在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程。

IPC方式有很多,在Android中常用的IPC方式包括Bundle、文件、MessengerAIDLContentProviderSocket等方式。本篇主要讲解使用AIDL的方式。

 

1.  AIDL

AIDL(Android Interface Definition Language)是一种接口定义语言。在跨进程通信时,客户端只需要使用一个代理,服务器只需要实现一个继承Binder并实现定义接口的Stub内部类。两者不需要知道对方的实现细节,所以说两者都是实现了同一个方法,只不过是客户端调用并通过跨进程真正在远程服务中执行,而大量的跨进程过程都是相同的,为了简化使用的成本Android使用了AIDL,只需要定义一个接口,就会自动生成客户端和服务器的跨进程实现代码,而如果想实现类似验证之类的操作,只需要在Stub的onTransact中进行相应的实现就可。

Messenger相比,AIDL最大的不同是具备多线程处理能力AIDL的使用主要分为以下三个步骤:

1)创建.aidl文件,定义接口;

2)在代码中实现接口,Android SDK会根据aidl文件生成接口,接口内部有一个名为Stub内部抽象类这个类继承了Binder类并实现aidl文件中定义的接口,我们需要拓展Stub类并实现里面的抽象方法

3)复写ServiceonBind(),返回Stub类的实现,将接口暴露给客户端。

2.  AIDL的简单使用示例

2.1  创建AIDL文件

本节将介绍一个最简单的AIDL使用示例,完成一个跨进程的远程加法计算过程。首先创建AIDL文件,并定义接口。在Android Studio中建立AIDL文件会默认在mian目录下创建aidl文件夹。这里创建了ImyAidlInterface接口以及add()方法。返回值类型为int

// IMyAidlInterface.aidl
package com.example.ipc_aidl;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
  int add(int num1,int num2);
}

该文件需要客户端和服务端各一份,这里为了简便示例在同一工程下进行,只需要一份即可,服务端使用android:process开启新进程,效果和两个工程下的通信是一样的。

2.2  生成java文件

编译一下工程,会在/build/generated/source/目录下生成一个aidl文件夹,且文件夹下的目录如下图所示,该java文件表示我们的aidl文件已经创建成功。

2.3  实现接口

声明接口后要实现接口,编写一个服务端,实例化IMyAidlInterface.Stub(),实现具体方法,并在onBind()中返回该Binder实例供客户端使用。

package com.example.ipc_aidl;
/**
 * 服务端
 * 实现接口并将其暴露给客户端
 * Created by SEU_Calvin on 2017/3/25.
 */
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class IRemoteService extends Service {
    private IBinder iBinder = new IMyAidlInterface.Stub() {
        @Override
        public int add(int num1, int num2) throws RemoteException {
            return num1 + num2;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }
}

最后别忘了在Manifest.xml中声明该服务,有一次不小心把该服务写在了<application>标签外面,然后客户端bindService()死活就是返回false,蠢的不行QAQ

<service android:name=".IRemoteService"    
 android:process=":remote">
</service>

2.4  客户端调用接口

最后是Activity中的逻辑:

package com.example.ipc_aidl;
/**
 * 客户端
 * 客户端调用远程接口
 * Created by SEU_Calvin on 2017/3/25.
 */
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.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity{
    private EditText et_num1;
    private EditText et_num2;
    private EditText edit_show_result;
    private Button btn_count;
    private int mNum1;
    private int mNum2;
    private int mTotal;
    private IMyAidlInterface iMyAidlInterface;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //服务绑定成功后调用,这里的service就是服务端onBind返回的iBinder
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidlInterface = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定服务
        Intent intent = new Intent(MainActivity.this,IRemoteService.class);
        //或者使用下面的方式设置Intent
        //intent.setComponent(new ComponentName("com.example.ipc_aidl","com.example.ipc_aidl.IRemoteService"));
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);

        et_num1 = (EditText)findViewById(R.id.et_num1);
        et_num2 = (EditText)findViewById(R.id.et_num2);
        edit_show_result = (EditText)findViewById(R.id.result);
        btn_count = (Button)findViewById(R.id.btn_count);
        btn_count.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mNum1 = Integer.parseInt(et_num1.getText().toString());
                mNum2 = Integer.parseInt(et_num2.getText().toString());
                try {
                    if(iMyAidlInterface == null){
                        Toast.makeText(MainActivity.this,"iMyAidlInterface is null",Toast.LENGTH_SHORT).show();
                    }else{
                        mTotal = iMyAidlInterface.add(mNum1,mNum2);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                edit_show_result.setText(mTotal+"");
            }
        });
    }


    @Override
    protected void onDestroy(){
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

首先执行bindService()方法绑定服务端的远程服务,绑定成功后会回调serviceConnection中的onServiceConnected()方法。在该方法中获取到服务端返回的Binder实例,并赋值给ImyAidlInterface类型的成员变量,调用它的add()方法即可调用远程服务实现两个加数的相加运算。

参考源码地址点击下载请大家多点赞支持~

有的朋友可能会说这种服务也太简单了吧,有没有更高级一点的用法呢,下一篇会介绍使用AIDL传递自定义的对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值