Android中的IPC——AIDL方式

AIDL是实现Android中IPC的一种方式。
通过AIDL我们将各种通信操作以接口方式进行定义,Android SDK则会按照AIDL的规则将AIDL编码成java类嵌入到应用中,然后我们就可以在APP运行时以调用函数的形式来进行IPC了。

与Messenger的区别

实际Messenger进行IPC本质也是以AIDL方式实现的,只不过通过上层接口封装我们不用自己实现AIDL的接口定义。Messenger与AIDL的区别在于——由于Messenger使用Handler处理消息序列,因此Service一次仅接受一个请求,适用于单线程的IPC通讯;AIDL则可以同时处理多个请求,不过这也要求我们的Service具备多线程处理能力。

构成

以下表格是APP与Service中组件及说明:

备注APP类型Service备注
在Service绑定回调中获取到AIDL对象onServiceConnectedConnectiononBindonBind声明周期调用时返回AIDL Stub
获取到AIDL对象,以调用接口AIDLVariableAIDL Stub实现AIDL定义的接口
需要与Service中定义相同AIDL定义文件AIDLAIDL定义文件需要与APP中定义相同


通过图片来展现这种关系,大致为:
在APP中使用AIDL

实现步骤

使用AIDL大致需要一下步骤:
1.在Service及APP工程中创建相同的AIDL文件,并定义相同接口。
2.在Service的onBind中返回AIDL的Stub
3.在APP中实现ServiceConnection,在onServiceConnected函数中调用Stub.asInterface获取到AIDL对象。
4.在事件响应中按需调用AIDL接口

首先,我们再App与Service工程中建立相同的AIDL接口:
App中——
App中的AIDL

Service中——
Service中的AIDL

创建好AIDL接口后,在其中添加一个简单的函数,接收两个int值,返回两者相加:

interface TestAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    //String basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
    //        double aDouble, String aString);

    int add(int alpha, int beta);
}

Android Studio默认添加了一个函数说明在AIDL中可接受的参数类型。

在定义完add接口后,Android Studio会触发Gradle自动生成interface的实现类,可以在build文件夹中找到:

package com.example.testaidlservice;
// Declare any non-default types here with import statements

public interface TestAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.testaidlservice.TestAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.example.testaidlservice.TestAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.testaidlservice.TestAidlInterface interface,
 * generating a proxy if needed.
 */
public static com.example.testaidlservice.TestAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.testaidlservice.TestAidlInterface))) {
return ((com.example.testaidlservice.TestAidlInterface)iin);
}
return new com.example.testaidlservice.TestAidlInterface.Stub.Proxy(obj);
}

// 余下略
}

asInterface即为在App中获取实现AIDL接口的Service的方法。

接下来,在Service工程中创建一个Service,在其中实现AIDL的接口:

public class TestService extends Service {

    private static final String TAG = TestService.class.getSimpleName();

    public TestService() {
    }

    // 实现AIDL接口,并在onBind中返回给App
    TestAidlInterface.Stub mStub = new TestAidlInterface.Stub() {

        @Override
        public int add(int alpha, int beta) throws RemoteException {
            return alpha + beta;
        }
    };


    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.i(TAG, "testService onBind");
        // 返回AIDL接口的对象
        return mStub;
    }

}

然后在App工程中,启动Service,并通过asInterface接口获取到AIDL的实现,进一步调用:

public class MainActivity extends AppCompatActivity {

    private Context mContext;

    private TextView resultText;
    private Button testAddButton;

    // 定义AIDL接口实现类的对象
    private TestAidlInterface testAidl;

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // onBind对象返回了AIDL的实现类,调用其中的asInterface方法来获取到可调用对象
            testAidl = TestAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

        mContext = this;

        resultText = (TextView) findViewById(R.id.result_text);
        testAddButton = (Button) findViewById(R.id.test_add);

        testAddButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 判断是否需要启动Service
                if (testAidl == null) {
                    Intent intent = new Intent();
                    intent.setAction("android.intent.action.TestAidlService");
                    intent.setPackage("com.example.testaidlservice");
                    bindService(intent, conn, Context.BIND_AUTO_CREATE);
                } else {
                    try {
                        // 调用AIDL接口获取返回值
                        String result = "result: " + testAidl.add(5, 8);
                        resultText.setText(result);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        Toast.makeText(MainActivity.this, "RemoteException", Toast.LENGTH_SHORT).show();
                    }

                }

            }
        });

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        unbindService(conn);
    }
}

安装两个APP后,无需启动Service,直接运行TestAidlApp。
此时含有AIDL的Service尚未启动,因此第一次点击按钮,会触发启动Service,这时Service会直接在另一个进程中启动;
然后再次点击按钮,就可以通过获取到的AIDL对象直接运行Service中方法,并拿到返回结果显示在界面上了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值