(每次学习一点xamarin就做个学习笔记和视频来加深记忆巩固知识)
如有不正确的地方,请帮我指正。
AIDL简介
  AIDL(Android Interface Definition Language)翻译为安卓接口定义语言,用于IPC(Inter-Process Communication)进程间通信。
  在xamarin学习笔记A08(安卓广播)中使用了Broadcast进行了跨进程通信,但是广播接收器是不允许开启线程的,所以在onReceive()方法中不能进行耗时操作,否则会报错,所以广播一般是用来打开其它组件,例如启动一个Service或者在状态栏创建一个Notification等。
  在xamarin学习笔记A11(安卓ContentProvider)中使用ContentProvider实现了跨进程通信,但它主要用于持久化数据的共享。
  而AIDL配合Service一起可以让两个进程持续的通信,AIDL效率也比上面的高。

AIDL个人认为
  个人认为AIDL语言只是用来帮助生成跨进程通信的代码的,帮助程序员少写代码,帮助程序员生成正确的代码。没有AIDL也可以手写,不过太麻烦。

通信过程
  安卓中大部分跨进程通信都是基于Binder机制。Binder翻译出来是“连接器”的意思。由于进程之间不能直接通信,所以需要“连接器”来帮助。
通过下面这张图来简单了解下跨进程通信过程。

  如上图所示,例如有一个A19B程序,它提供BookService,允许传入一个bookId来返回给别人一个Book对象。还有一个A19程序,它想访问这个Service,那么大概的流程是这样的:
A. 首先A19B这个程序安装到安卓中后,会在ServiceManage中注册BookService服务。
B. A19这个程序的MainActivity通过this.BindService()来得到IBinder对象,即得到了连接BookService的“连接器”。BindService方法会触发很多内部复杂的操作,比如Binder程序把A19程序传递过来的请求的服务名去SerivceManage中查询对应的服务,然后创建一个指向该服务的“连接器”对象IBinder以供A19使用。
C. 有了“连接器”对象IBinder,就可以通过此连接器来访问远程BookService服务了,可以调用GetBook()方法来得到Book对象了。

  那么具体该如何做呢?
1.首先两个程序都新建一个一样的Book类且必须实现了IParcelabler接口。

public class Book : Java.Lang.Object, IParcelable{public int BookId { get; set; }public string BookName { get; set; }public double BookPrice { get; set; }public Book(){}//打包数据public void WriteToParcel(Parcel dest, [GeneratedEnum] ParcelableWriteFlags flags){dest.WriteInt(BookId);dest.WriteString(BookName);dest.WriteDouble(BookPrice);}public int DescribeContents(){return 0; //不用管,填0即可}private static readonly MyParcelableCreator<Book> _creator = new MyParcelableCreator<Book>(GetBook);//解包数据private static Book GetBook(Parcel parcel){Book book = new Book();book.BookId = parcel.ReadInt();book.BookName = parcel.ReadString();book.BookPrice = parcel.ReadDouble();return book;}[ExportField("CREATOR")]public static MyParcelableCreator<Book> GetCreator(){return _creator;}
}

2.其次两边都新建一个Book.aidl文件,内容如下

package A19B;
parcelable Book;

这个aidl文件定义了这是个parcelable(可序列化)的Book,它属于A19B这个包。

3.然后两边都新建一个IBook.aidl文件,内容如下

package A19B;
import A19B.Book;
interface IBook
{Book GetBook(in int bookId);
}

此aild文件定义了一个IBook接口,里面有一个GetBook()方法,因为它使用了Book类,所以得import A19B.Book;。

4.设置这个两个aidl文件的生成操作,如下图

编译项目后会在“obj\Debug\aidl”目录下生成Book.cs,IBook.cs跨进程通信代码。(个人认为生成的Book.cs没啥用,我也没用到)
Book.cs代码如下

// This file is automatically generated and not supposed to be modified.
using System;
using Boolean = System.Boolean;
using String = System.String;
using List = Android.Runtime.JavaList;
using Map = Android.Runtime.JavaDictionary;namespace A19B
{}

IBook.cs代码如下

namespace A19B
{public interface IBook : global::Android.OS.IInterface{global::A19B.Book GetBook(int bookId);}public abstract class IBookStub : global::Android.OS.Binder, global::Android.OS.IInterface, A19B.IBook{const string descriptor = "A19B.IBook";public IBookStub(){this.AttachInterface(this, descriptor);}public static A19B.IBook AsInterface(global::Android.OS.IBinder obj){if (obj == null)return null;var iin = (global::Android.OS.IInterface)obj.QueryLocalInterface(descriptor);if (iin != null && iin is A19B.IBook)return (A19B.IBook)iin;return new Proxy(obj);}public global::Android.OS.IBinder AsBinder(){return this;}protected override bool OnTransact(int code, global::Android.OS.Parcel data, global::Android.OS.Parcel reply, int flags){switch (code){case global::Android.OS.BinderConsts.InterfaceTransaction:reply.WriteString(descriptor);return true;case TransactionGetBook:{data.EnforceInterface(descriptor);int arg0 = default(int);arg0 = data.ReadInt();var result = this.GetBook(arg0);reply.WriteNoException();if (result != null) { reply.WriteInt(1); result.WriteToParcel(reply, global::Android.OS.ParcelableWriteFlags.ReturnValue); } else reply.WriteInt(0);return true;}}return base.OnTransact(code, data, reply, flags);}public class Proxy : Java.Lang.Object, A19B.IBook{global::Android.OS.IBinder remote;public Proxy(global::Android.OS.IBinder remote){this.remote = remote;}public global::Android.OS.IBinder AsBinder(){return remote;}public string GetInterfaceDescriptor(){return descriptor;}public global::A19B.Book GetBook(int bookId){global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain();global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain();global::A19B.Book __result = default(global::A19B.Book);try{__data.WriteInterfaceToken(descriptor);__data.WriteInt(bookId);remote.Transact(IBookStub.TransactionGetBook, __data, __reply, 0);__reply.ReadException();__result = __reply.ReadInt() != 0 ? (global::A19B.Book)global::Android.OS.Bundle.Creator.CreateFromParcel(__reply) : null;}finally{__reply.Recycle();__data.Recycle();}return __result;}}internal const int TransactionGetBook = global::Android.OS.Binder.InterfaceConsts.FirstCallTransaction + 0;public abstract global::A19B.Book GetBook(int bookId);}
}

生成的IBookStub这个名字中的Stub很形象,Stub翻译为“存根”,例如,平时我们去寄快递时双方会各留一张存根。
其中特别要注意是的这地方生成的是错的

global::Android.OS.Bundle.Creator.CreateFromParcel(__reply)

应改为

global::A19B.Book.GetCreator().CreateFromParcel(__reply)

我用是VS2017 15.4.0版本,可能在下个新版本会解决掉这个BUG吧。
不过没关系,把这个文件的代码全部复制到剪切版,然后自已新建一个IBook.cs文件,还不行,得先清理解决方案,不然前面自动生成的IBook.cs文件还在,导致不能新建,同时还得把两个aidl文件的生成操作改为“无”。
新建后粘贴代码,修改那句错了的地方,并把这个IBook.cs文件复制到A19项目里,不需做任何修改,命名空间都不要改。如果没有这个BUG,则不需要这么麻烦,两个项目都会根据aidl文件自动生成跨进程通信代码。
这样就完成了跨进程通信代码的生成这一步了。

5.在A19B程序中新建一个BookService服务

[Service(Exported =true, Enabled =true)][IntentFilter(new string[] {"com.A19B.BookService"})]public class BookService : Service{public override IBinder OnBind(Intent intent){return new BookBinder();}private class BookBinder : IBookStub{public override Book GetBook(int bookId){if (bookId == 1){Book book = new Book();book.BookId = 1;book.BookName = "C#高级编程";book.BookPrice = 88.88;return book;}else return null;}}
}

这里定义了一个BookBinder类来继承生成的抽象类IBookStub,实现GetBook就可以了。然后在OnBind()方法中实例化此类的对象返回给外部使用。

6.在A19项目的MainActivity中访问BookService,上主要代码

public class MainActivity : AppCompatActivity
{private TextView _textView;private BookServiceConnection conn;//省略其它代码private void BindRemoteService()//绑定远程服务{Intent intent = new Intent("com.A19B.BookService");if (intent != null){if (conn == null){conn = new BookServiceConnection();}this.BindService(intent, conn, Bind.AutoCreate);}}private void InvokeRemoteService()//调用远程服务{if (conn != null){Book book = conn.IBook.GetBook(1);if(book!=null)_textView.Text = string.Format("BookId={0} BookName={1} BookPrice={2}", book.BookId, book.BookName, book.BookPrice);}}}public class BookServiceConnection : Java.Lang.Object, IServiceConnection{public IBook IBook { get; private set; }public void OnServiceConnected(ComponentName name, IBinder service){IBook = IBookStub.AsInterface(service);}}
}

需要定义一个BookServiceConnection类并实现IServiceConnection接口,因为在调用this.BindService()方法时需要一个实现了此接口的对象,成功绑定远程服务后会回调OnServiceConnected方法把“连接器”对象IBinder传过来。
因为“连接器”对象实现了IBook接口,所以可以通过AsInterface转换,然后存到public IBook IBook变量中以供使用。
最后通过Book book = conn.IBook.GetBook(1);调用了远程服务获得了Book对象。表面上看像是直接调用了BookSerive服务,实际内部是通过Binder驱动来调用的。

需要注意
  在Android5.0及以上系统中需要显式声明Intent才能启动Service。

//从隐式声明的Intent中创建一个显式声明的Intent(在Android5.0及以上系统中需要显式声明Intent才能启动Service)private Intent CreateExplicitFromImplicitIntent(Context context, Intent implicitIntent){PackageManager pm = context.PackageManager;//查出所有的能匹配这个隐式意图的服务列表IList<ResolveInfo> resolveInfo = pm.QueryIntentServices(implicitIntent, 0);if (resolveInfo == null || resolveInfo.Count != 1){return null;}ResolveInfo serviceInfo = resolveInfo[0];string packageName = serviceInfo.ServiceInfo.PackageName;//取出包名string className = serviceInfo.ServiceInfo.Name;//取出服务名ComponentName component = new ComponentName(packageName, className);//用包名和服务名来创建一个ComponentName对象//拿隐式意图对象implicitIntent作为构造参数,来创建一个新的显示的意图Intent explicitIntent = new Intent(implicitIntent);explicitIntent.SetComponent(component);//设置显示意图的组件名对象return explicitIntent;}private void BindRemoteService()//绑定远程服务{Intent intent = new Intent("com.A19B.BookService");if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)//(在Android5.0及以上系统中需要显式声明Intent才能启动Service){intent = CreateExplicitFromImplicitIntent(this, intent);}if (_bookServiceConnection == null){_bookServiceConnection = new BookServiceConnection();}this.BindService(intent, _bookServiceConnection, Bind.AutoCreate);Toast.MakeText(this,"绑定远程服务", ToastLength.Short).Show();}

代码和视频在我上传的CSDN资源中http://download.csdn.net/download/junshangshui/10121804

xamarin学习笔记A19(安卓AIDL)相关推荐

  1. Xamarin 学习笔记 - 配置环境(Windows iOS)

    2019独角兽企业重金招聘Python工程师标准>>> 本文翻译自CodeProject文章:https://www.codeproject.com/Articles/1223980 ...

  2. xamarin 学习笔记02- IOS Simulator for windows 安装

    微软发布了在window下的ios模拟器 下载 ios模拟器 并安装在windows系统上. Xamarin for Visual Studio 和 网络上的 Mac 中的 Xamarin.iOS 开 ...

  3. 小罗学习笔记之安卓的存储路径(持续完善)

    这两天给app集成了DiskLruCache,参考郭神的文章 Android DiskLruCache完全解析,硬盘缓存的最佳方案 http://blog.csdn.net/guolin_blog/a ...

  4. 【安卓学习笔记】安卓的事件处理

    安卓提供了两种方式的事件处理:基于回调的事件处理和基于监听的事件处理. 基于监听的事件处理 基于监听的事件处理一般包含三个要素,分别是: Event Source(事件源):事件发生的场所,通常是各个 ...

  5. 安卓学习笔记:安卓11访问/读写 Android/data 目录

    省流提示:采用android studio工具开发,记录一次低级的开发,避免以后忘记或者踩坑. 最近有个业余项目开发到一小半,过程中需要读写 Android/data目录的文件,采用常规的文件操作总是 ...

  6. 安卓学习笔记之骚扰拦截

    安卓学习笔记之骚扰拦截 1.监听电话状态 2.检测来电号码是否匹配拦截条件 3.若匹配,则挂断电话 实例代码: 获取TelephonyManager 对象,并监听来电状态 TelephonyManag ...

  7. 2020年安卓学习笔记目录

    文章目录 一.讲课笔记 二.安卓案例 三.安卓实训项目 四.学生安卓学习博客 五.安卓课后作业 (一)界面设计练习 1.制作登录界面 2.制作部队管理界面 3.制作灭火救援界面 4.制作交付界面 5. ...

  8. 安卓学习笔记07:事件处理、窗口跳转与传递数据

    文章目录 零.学习目标 一.三个基本控件 1.标签控件(TextView) 2.编辑框控件(EditText) 3.按钮控件(Button) 二.安卓事件处理机制 (一)安卓事件处理概述 (二)安卓事 ...

  9. Sencha学习笔记2:打包您的第一个Sencha安卓应用apk安装包

    通过上一篇翻译的官方文章的介绍我们对sencha有了初步的印象,同时我们也通过该向导生成了第一个示例应用代码框架,那么下一步可能很多人都觉得应该根据该向导所提示的去看一下一个应用是如何建立起来的详细信 ...

最新文章

  1. ios架构篇-1 项目组织架构
  2. java opencv4.40图片实现人脸识别(2)
  3. Angular中父子组件传值@Input @Output @ViewChild最全面最简单的总结
  4. HTML5 SVG
  5. AsyncDisplayKit官方文档个人翻译
  6. python爬取微博热搜并存入表格_python爬虫进阶之爬取微博热搜存入Mysql
  7. 安装linux环境及相关包方法
  8. 苹果iPod设计及商业操作内幕
  9. 如何实现某个软件的单独断网/稳定地解决fluent断网计算中止问题/tecplot联网后打开程序出现报错问题
  10. 计算机和材料成型及控制工程,材料成型及控制工程专业属于什么门类
  11. R语言实现 懒惰学习——使用近邻分类
  12. 缩写月份单词python_月份的英文单词、缩写及由来
  13. Mac软件最全的下载网站top10
  14. FinalShell Mac OS版安装
  15. 2020李宏毅学习笔记——14.Convolution Netural Network
  16. Java常见面试题含答案(第一期)
  17. Python +大数据-知行教育(四)-意向用户主题看板_全量流程
  18. 想玩 NAS? 群晖NAS 的选购 配件搭配以及硬盘 RAID指南
  19. 无固定公网IP,群晖动态解析域名到动态公网IP
  20. z-index 应用简单总结

热门文章

  1. 揭秘 手机群控 带来的利益
  2. 国产开源项目管理软件ZenTao
  3. 如何将ppt演示文稿上传到微信公众号?
  4. 团队开发工具之一——Wiki
  5. 强网杯团队赛---Misc
  6. java jpeg rpg_史上最骚RPG制作第三期 java端数据的插入和查询
  7. HTML5期末大作业:电影票务网站设计——电影票务网站整套(24页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码
  8. 怎样成为一个PS高手
  9. EBS中应用,职责,数据组,请求组等关系
  10. python创建时间序列_python 时间序列