Android IPC通信之AIDL理解

Android IPC通信之AIDL理解

本文就我自己在使用aidl过程中的一些心得与大家分享:
定义 服务端 A 客户端 B

服务端A操作

  • 定义aidl文件
  • 定义aidl的方法,可传的参数类型:基本数据类型、ArrayList、String,List,Map,CharSequence等类其他AIDL接口类型、所有Parcelable的类。
  • 构建Service类,在onBind方法中需要返回一个IBind的实例,aidl.Stub()方法恰好返回IBind类型,因此在此处返回aidl.Stub(){实现方法};此处实现aidl中定义的方法;
  • 注册服务。

客户端B操作

  • 定义aidl文件,与服务端的aidl文件完全相同,可直接复制过来,且包名也必须相同(一定注意,个人理解是Android底层在aidl通信时会直接调用服务端的aidl文件进行使用,客户端的aidl文件名称必须指向服务端,不然调用不到,无法通信,而内容一致是方便客户端对方法的调用。(个人理解,如有错误,请指出))。
  • 绑定服务,隐式绑定服务端的Service(Android5.0后必须用显式方式,不然会报错,但此处需用隐式,解决方法如下:
Intent intent = new Intent();
        intent.setAction("com.a592n.dizner.thrtest.TestgService");
        Intent eintent = new Intent(getExplicitIntent(this,intent));
        b = bindService(eintent, connection, BIND_AUTO_CREATE);

    public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }

);

  • 此处必须使用bindService()方法来启动服务(记得调用unBindService()),在ServiceConnection的实现类中得到IBind实例,通过IBind获取aidl实例,aidl.Stub.asInterface(iBinder)即可得到。
  • 通过aidl实例对服务端进行操作。

举例如下

  • 服务端
    aidl文件:
// ITestAidlInterface.aidl
package com.a592n.dizner.thrtest;

// Declare any non-default types here with import statements

interface ITestAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    String basicTypes(String aString);
}

Service:

@Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
//        throw new UnsupportedOperationException("Not yet implemented");
        return new ITestAidlInterface.Stub(){

            @Override
            public String basicTypes(String aString) throws RemoteException {
                Log.d("远程会话消息:",aString);
                return aString;
            }
        };
    }
  • 客户端
    aidl文件:
// ITestAidlInterface.aidl
package com.a592n.dizner.thrtest;

// Declare any non-default types here with import statements

interface ITestAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    String basicTypes(String aString);
}

MainActivity 内容:

public class MainActivity extends AppCompatActivity {
    private ITestAidlInterface service;
    private int i = 0;
    private Button bt_txt;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            service = ITestAidlInterface.Stub.asInterface(iBinder);
            try {
                String s = service.basicTypes("远程服务连接成功");
                Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Toast.makeText(MainActivity.this, "远程服务连接失败", Toast.LENGTH_LONG).show();
        }
    };
    private boolean b;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.setAction("com.a592n.dizner.thrtest.TestgService");
        Intent eintent = new Intent(getExplicitIntent(this,intent));
        b = bindService(eintent, connection, BIND_AUTO_CREATE);
        bt_txt = (Button) findViewById(R.id.bt_txt);
    }

    public void onClick(View view) {

        try {
            if (b)
                bt_txt.setText(service.basicTypes(String.valueOf(i++)));
            else
                Toast.makeText(MainActivity.this, "服务未连接", Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }
}

AIDL通讯就完成了。

切记

本案例中的aidl文件是使用AS自动生成,在写完两端的aidl文件后,保证内容一致,包名一致,包路径也必须一致,重命名aidl包名时选择重置的是DirectoryName,否则项目包名就被修改了。

参考引用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值