AIDL-AndRoid接口描述语言实现跨进程通讯

2023-11-08 04:48

本文主要是介绍AIDL-AndRoid接口描述语言实现跨进程通讯,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢?  显然, Java中不允许跨进程内存共享. 因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦.

AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.

AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.

具体实现步骤如下:

1、创建AIDL文件, 在这个文件里面定义接口, 该接口定义了可供客户端访问的方法和属性。 如: ITaskBinder.adil

package com.cmcc.demo;

 

import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

   

    boolean isTaskRunning();

       

    void stopRunningTask();   

   

    void registerCallback(ITaskCallback cb);   

  

    void unregisterCallback(ITaskCallback cb);

}

其中: ITaskCallback在文件ITaskCallback.aidl中定义:

package com.cmcc.demo;

 

interface ITaskCallback {

    void actionPerformed(int actionId);

}

注意: 理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类, 不过在Eclipse中,目前的ADT不支持Bundle做为参数, 据说用Ant编译可以, 我没做尝试.

2、编译AIDL文件, 用Ant的话, 可能需要手动, 使用Eclipse plugin的话,可以根据adil文件自动生产java文件并编译, 不需要人为介入.

3、在Java文件中, 实现AIDL中定义的接口. 编译器会根据AIDL接口, 产生一个JAVA接口。这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。接下来就需要自己去实现自定义的几个接口了.

ITaskBinder.aidl中接口的实现, 在MyService.java中接口以内嵌类的方式实现:

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

        public void stopRunningTask() {

            //@TODO

        }

       

        public boolean isTaskRunning() {

            //@TODO

            return false;

        }

       

        public void registerCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.register(cb);

        }

        public void unregisterCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.unregister(cb);

        }

};

在MyActivity.java中ITaskCallback.aidl接口实现:

private ITaskCallback mCallback = new ITaskCallback.Stub() {

        public void actionPerformed(int id) {

           //TODO

            printf("callback id=" + id);

        }

};

4、向客户端提供接口ITaskBinder, 如果写的是service,扩展该Service并重载onBind ()方法来返回一个实现上述接口的类的实例。这个地方返回的mBinder,就是上面通过内嵌了定义的那个. (MyService.java)

    public IBinder onBind(Intent t) {

        printf("service on bind");

        return mBinder;

}

在Activity中, 可以通过Binder定义的接口, 来进行远程调用.

5、在服务器端回调客户端的函数. 前提是当客户端获取的IBinder接口的时候,要去注册回调函数, 只有这样, 服务器端才知道该调用那些函数在:MyService.java中:

    void callback(int val) {

        final int N = mCallbacks.beginBroadcast();

        for (int i=0; i<N; i++) {

            try {

                mCallbacks.getBroadcastItem(i).actionPerformed(val);

            } catch (RemoteException e) {

                // The RemoteCallbackList will take care of removing

                // the dead object for us.

            }

        }

        mCallbacks.finishBroadcast();

}

AIDL的创建方法:

AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。由于远程调用的需要, 这些参数和返回值并不是任何类型.下面是些AIDL支持的数据类型:

1. 不需要import声明的简单Java编程语言类型(int,boolean等)

2. String, CharSequence不需要特殊声明 3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型. ((另外: 我没尝试Parcelables, 在Eclipse+ADT下编译不过, 或许以后会有所支持).下面是AIDL语法: // 文件名: SomeClass.aidl // 文件可以有注释, 跟java的一样 // 在package以前的注释, 将会被忽略. // 函数和变量以前的注释, 都会被加入到生产java代码中.package com.cmcc.demo; // import 引入语句import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

    //函数跟java一样, 可以有0到多个参数 ,可以有一个返回值

    boolean isTaskRunning();

       

    void stopRunningTask();   

    //参数可以是另外的一个aidl定义的接口

    void registerCallback(ITaskCallback cb);   

  

void unregisterCallback(ITaskCallback cb);

//参数可以是String, 可以用in表入输入类型, out表示输出类型.

int getCustomerList(in String branch, out String[] customerList);

} 实现接口时有几个原则:

.抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的..IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。 也就是IPC调用会挂起应用程序导致界面失去响应. 这种情况应该考虑单起一个线程来处理..不能在AIDL接口中声明静态属性。IPC的调用步骤:

 1. 声明一个接口类型的变量,该接口类型在.aidl文件中定义。 2. 实现ServiceConnection。 3. 调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递.  4. 在ServiceConnection.onServiceConnected()实现中,你会接收一个IBinder实例(被调用的Service). 调用    YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。 5. 调用接口中定义的方法。 你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。 6. 断开连接,调用接口实例中的ApplicationContext.unbindService()

下面是整个程序:

1. ITaskCallback.aidl

 

package com.cmcc.demo;

 

interface ITaskCallback {

    void actionPerformed(int actionId);

}

 

2. ITaskBinder.aidl

package com.cmcc.demo;

 

import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

   

    boolean isTaskRunning();

       

    void stopRunningTask();   

   

    void registerCallback(ITaskCallback cb);   

  

    void unregisterCallback(ITaskCallback cb);

}

 

3.  MyService.java

package com.cmcc.demo;

 

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteCallbackList;

import android.os.RemoteException;

import android.util.Log;

 

public class MyService extends Service {

       

    @Override

    public void onCreate() {

        printf("service create");

    }

   

    @Override

    public void onStart(Intent intent, int startId) {

        printf("service start id=" + startId);

        callback(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.e("TAG", "###################------ " + str + "------");

    }

   

    void callback(int val) {

        final int N = mCallbacks.beginBroadcast();

        for (int i=0; i<N; i++) {

            try {

                mCallbacks.getBroadcastItem(i).actionPerformed(val);

            } catch (RemoteException e) {

                // The RemoteCallbackList will take care of removing

                // the dead object for us.

            }

        }

        mCallbacks.finishBroadcast();

    }

   

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

        public void stopRunningTask() {

           

        }

       

        public boolean isTaskRunning() {

            return false;

        }

       

        public void registerCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.register(cb);

        }

        public void unregisterCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.unregister(cb);

        }

    };

   

    final RemoteCallbackList<ITaskCallback> mCallbacks

        = new RemoteCallbackList<ITaskCallback>();

}

 

4. MyActivity.java

package com.cmcc.demo;

 

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.graphics.Color;

import android.os.Bundle;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

import android.view.View;

import android.view.ViewGroup;

import android.view.View.OnClickListener;

import android.widget.AbsoluteLayout;

import android.widget.Button;

import android.widget.LinearLayout;

import android.widget.RelativeLayout;

import android.widget.TextView;

 

import java.io.BufferedReader;

import java.io.File;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.PrintWriter;

 

public class MyActivity extends Activity {

   

    private Button btnOk;

    private Button btnCancel;

   

    @Override

    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);

       

        setContentView(R.layout.test_service);

       

        btnOk = (Button)findViewById(R.id.btn_ok);

        btnCancel = (Button)findViewById(R.id.btn_cancel);

       

        btnOk.setText("Start Service");

        btnCancel.setTag("Stop Service");

       

        btnOk.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                onOkClick();

            }

        });

 

        btnCancel.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                onCancelClick();

            }

        });

    }

   

    void onOkClick() {

        Bundle args = new Bundle();       

       

        Intent intent = new Intent(this, MyService.class);

        intent.putExtras(args);  

       

        //printf("send intent to start");

       

        //startService(intent);

        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        startService(intent);

    }

   

    void onCancelClick() {

        Intent intent = new Intent(this, MyService.class);

        //printf("send intent to stop");

       

        unbindService(mConnection);

        //stopService(intent);

    }

   

    private void printf(String str) {

        Log.e("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);

            } 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);

        }

    };

}


本文来自CSDN博客,转载:http://blog.csdn.net/zhqingyun163/archive/2009/11/2**876347.aspx

这篇关于AIDL-AndRoid接口描述语言实现跨进程通讯的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/367952

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现