您的位置:首页 > 大数据 > 人工智能

AIDL进程间传递复杂数据类型—AIDL传递其他AIDL接口

2015-08-15 14:32 555 查看
AIDL进程间传递复杂数据类型系列:

AIDL进程间传递复杂数据类型—AIDL传递其他AIDL接口

AIDL进程间传递复杂数据类型—AIDL传递android.os.Parcelable接口

=========================================

首先我们来写一个简单的服务:

AIDL文件:

interface IManager {
    int add(int x , int y);
    int min(int x , int y );
}


客户端文件MainActivity.java:

public class MainActivity extends Activity {

    private IManager manager;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("MyService", "onServiceConnected");
            //得到本地代理对象
            manager = IManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

    public void bindService(View view) {
        Log.i("MyService", "bindService");
        Intent intent = new Intent("com.startservice.MyService");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    public void unbindService(View view) {
        unbindService(connection);
    }

    public void caculate(View view){
        if (manager == null) {
            Toast.makeText(this, "请绑定服务", Toast.LENGTH_SHORT).show();
        } else {
            int result = 0;
            try {
                result = manager.add(4, 5);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Toast.makeText(this, result + "",Toast.LENGTH_SHORT).show();
        }
    }
}


服务端代码为MyService.java

public class MyService extends Service {
    private Manager manager = new Manager();

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("MyService", "onBind");
        return manager;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i("MyService", "onDestroy");
        super.onDestroy();
    }

    class Manager extends IManager.Stub{

        @Override
        public int add(int x, int y) throws RemoteException {
            return x + y;
        }

        @Override
        public int min(int x, int y) throws RemoteException {
            return x - y;
        }
    }
}


layout布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:text="绑定服务"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="bindService"/>

    <Button
        android:text="解绑服务"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="unbindService"/>

    <Button
        android:text="计算"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="caculate"/>

</LinearLayout>


当我们在使用bindService来绑定服务的时候,只需要在AndrodManifest配置文件中,在Service的属性中加上android:process=”:remote”,remote这个名字可以自定义,我们就可以在一个新的进程中绑定一个服务。

代码如下:

<service
    android:name="com.bindserviceclient.MyService"
    android:process=":remote"
    android:enabled="true"
    android:exported="true" >
    <intent-filter>
        <action android:name="com.bindservice.MyService"/>
    </intent-filter>
</service>


上面的过程很简单,也很熟悉,按照流程走就可以了。

上面只是传递了简单的int类型的值,这里想说的就是使用AIDL进行这种进程间通信的时候,可以传递哪些数据类型。

下面进行了一些总结。

1.AIDL支持Java原始数据类型

2.AIDL支持String和CharSequence

3.AIDL支持传递其他AIDL接口,但你引用的每个AIDL接口都需要一个import语句,即使位于同一个包中

4.AIDL支持传递实现了android.os.Parcelable接口的复杂类型,同样在引用这些类型时也需要import语句

5.AIDL支持java.util.List和java.util.Map,但是有一些限制。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需要为Parcelable提供import语句。

具体为什么AIDL可以传递这些数据类型以及它可以传递的详细数据类型可以参考文章浅析Android中Parcel类

另外需要注意的是:非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。

我们这里主要介绍后面的第3和第4种,前面的两种比较简单,我们上面代码已经展示了用法,把第3种和第4种弄明白了,第5种应该没什么问题。

一、AIDL传递其他AIDL接口

在客户端和服务端分别有两个AIDL文件,是一个是绑定服务使用,一个是传递使用

// IManager.aidl
package com.xxx.cn.client;
import com.xxx.cn.client.IListener;

interface IManager {
    int add(int x , int y);
    void registerListener(in IListener listener);
}


// IListener.aidl
package com.xxx.cn.client;

interface IListener {
    void onChange(int x);
}


可以看到IListener是IManager里面registerListener的一个参数,即这里传递的就是AIDL接口。

服务端代码:

//MyService.java:
package com.xxx.cn.client;

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 {
    private static final String TAG = "MyService";

    private IListener mListener;
    private Manager manager = new Manager();

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return manager;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy");
        super.onDestroy();
    }

    class Manager extends IManager.Stub{

        @Override
        public int add(int x, int y) throws RemoteException {
            return x + y;
        }

        @Override
        public void registerListener(IListener listener) throws RemoteException {
            mListener = listener;

            //得到这个listner后,就可以在需要的地方回调客户端的onChange函数
            mListener.onChange(4);
            Log.i(TAG, "onChange");
        }
    }
}


客户端代码:

//MainActivity.java:
package com.xxx.cn.client;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    class Listener extends IListener.Stub {

        @Override
        public void onChange(int x) throws RemoteException {
            Log.i(TAG, "服务端回调了方法onChange,x = " + x);
        }
    }

    private IManager manager;
    private Listener mListener = new Listener();

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected");
            //得到本地代理对象
            manager = IManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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

    public void bindService(View view) {
        Log.i(TAG, "bindService");
        Intent intent = new Intent("com.bindservice.MyService");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    public void unbindService(View view) {
        unbindService(connection);
    }

    public void caculate(View view){
        if (manager == null) {
            Log.i(TAG, "请绑定服务");
        } else {
            int result = 0;
            try {
                result = manager.add(4, 5);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(TAG, "result=" + result);
        }
    }

    public void listener(View view){
        if (manager == null) {
            Log.i(TAG, "请绑定服务");
        } else {
            try {
                manager.registerListener(mListener);
                Log.i(TAG, "注册监听");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


客户端布局文件activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:text="绑定服务"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="bindService"/>

    <Button
        android:text="解绑服务"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="unbindService"/>

    <Button
        android:text="计算"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="caculate"/>

    <Button
        android:text="传递监听"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="listener"/>
</LinearLayout>


可以看到,我们服务直接传递了一个IListener类型的参数去在服务端注册了一个回调,然后在服务端就可以回调客户端的实现函数。这个非常的有用。

运行代码,首先启动服务端,然后启动客户端:

客户端的运行界面如下:



首先点击”绑定服务”

客户端打印的Log如下:



服务端打印的Log如下:



当点击”计算”

客户端打印的Log如下:



当点击”传递监听”

客户端打印的Log如下:



服务端打印的Log如下:



我们可以看到,服务端回调了mListener.onChange(4),客户端确实执行了这个函数,并且得到了服务端传递过来的这个值。

第二种参看下面这篇文章:

AIDL进程间传递复杂数据类型—AIDL传递android.os.Parcelable接口
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: