《android开发艺术探索》读书笔记(二)--IPC机制
No1:
在android中使用多进程只有一种方法,那就是给四大组件在AndroidMenifest中指定android:process属性。
No2:
默认进程的进程名是包名。
No3:
":"要加上当前包名,进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中;另外一种属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
No4:
Android系统会为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据。
No5:
Android为每一个应用(或者说每个进程)分配了一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本。修改一个进程中的值只会影响当前进程
No6:
所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败,这也是多进程所带来的主要影响。
No7:
使用多进程会造成几个问题:
(1)静态成员和单例模式完全失效
(2)线程同步机制完全失效(不是一块内存,不同进程锁不是同一个对象)
(3)SharedPerference的可靠性下降(SharedPreferences不支持两个进程同时去执行写操作)
(4)Application会多次创建(相当于应用重新启动,运行在同一个进程中的组件时属于同一个虚拟机和同一个Application的)
No8:
进程间通信的方式有:Bundle、Intent、文件共享、SharedPerference、AIDL、Messenger、ContentProvider、Socket
No9:
当我们需要通过Intent和Binder传输数据时就需要使用Parcelable或者Serializable。
No10:
实际上,不声明serialVersionUID同样也可以实现序列化,但是这将会对反序列化过程产生影响。
No11:
Serializable序列化
//序列化过程
User user = new User(0,"jake",true);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close(); //反序列化过程
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User newUser = (User)in.readObject();
in.close();
No12:
serialVersionUID的详细工作机制是这样的:
序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中(也可能是其他中介),当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变换,比如成员变量的数量、类型可能发生了变化,这个时候是无法正常反序列化的。
No13:
1.静态成员变量属于类不属于对象,所以不会参与序列化过程
2.用transient关键字标记的成员变量不参与序列化过程
No14:
实现了Parcelable接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。
No15:
序列化由writeToParcel方法来完成
反序列化功能由CREATOR来完成
内容描述功能由describeContents方法来完成
No16:
系统已经为我们提供了许多实现了Parcelable接口的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,同时List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的。
No17:
Serializable是java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量I/O操作。Parcelable缺点就是使用起来稍微麻烦点,但是它的效率很高,主要用在内存序列化上。首选Parcelable
将对象序列化到存储设备中或者将对象序列化后通过网络传输也都是可以的,但是这个过程会稍显复杂,因此这两种情况下建议使用Serializable。
No18:
从IPC角度来说,Binder是android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有;
从Android Framework角度来说,Binder是ServiceManager链接各种Manager(ActivityManager、WindowManager等等)和ManagerService的桥梁;
从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
No19:
手动实现一个Binder步骤:
1.声明一个继承IInterface接口的AIDL性质的接口,接口中只有一个asBinder方法。
2.实现Stub类和Stub类中的Proxy代理类。
No20:
AIDL文件的本质是系统为我们提供了一种快速实现Binder的工具。
No21:
给Binder设置死亡代理,监听Binder是否死亡
声明接口DeathRecipient,其内部只有一个方法binderDied,当Binder死亡的时候,系统会回调binderDied方法,然后我们就可以移出之前绑定的binder代理并重新绑定远程服务
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient(){
@Override
public void binderDied(){
if(mBookManager == null) {
return;
}
mBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
mBookManager = null;
}
}
在客户端绑定远程服务成功后,给binder设置死亡代理
mService = IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient,0);
另外,通过Binder的方法isBinderAlive也可以判断Binder是否死亡。
No22:
跨进程通信方式
1.通过在Intent中附加extras来传递信息
2.通过共享文件的方式
3.采用Binder方式
4.ContentProvider天生就是支持跨进程通信的
5.网络通信可以实现数据传递,所以Socket也可以实现IPC
No23:
Messenger的使用方法很简单,它对AIDL做了封装。由于它一次处理一个请求,因此在服务端我们不用考虑线程同步的问题,因为服务端中不存在并发执行的情形。Messenger是以串行的方式处理客户端发来的消息。
No24:
AIDL文件支持的数据类型:
1.基本数据类型
2.String和CharSequence
3.ArrayList,且里面每个元素都必须能够被AIDL支持
4.HashMap,且里面每个元素都必须能够被AIDL支持,包括key和value
5.Parcelable,所有实现了Parcelable接口的对象
6.AIDL,所有的AIDL接口本身
No25:
AIDL中每个实现了Parcelable接口的类都需要按照上面那种方式去创建相应的AIDL文件并声明那个类为parcelable。
No26:
CopyOnWriteArrayList支持并发读/写。AIDL方法是在服务端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以我们要在AIDL方法中处理线程同步,而我们直接使用CopyOnWriteArrayList来进行自动的线程同步。
No27:
AIDL中所支持的是抽象的List,而List只是一个接口,因此虽然服务器返回的是CopyOnWriteArrayList,但是在Binder中会按照List的规范去访问数据并最终形成一个新的ArrayList传递给客户端(AIDL中能够使用的List只有ArrayList)。
No28:
对象是不能跨进程传输的,对象的跨进程传输本质上都是反序列化的过程,这就是为什么AIDL中的自定义对象都必须要实现Parcelable接口的原因。
RemoteCallbackList是系统专门提供的用于删除跨进程listener的接口。RemoteCallbackList是一个泛型,支持管理任意的AIDL接口,这点从它的声明就可以看出,因为所有的AIDL接口都继承自IInterface接口。
RemoteCallbackList:当客户端解注册的时候,我们只要遍历服务端所有的listener,找出那个和解注册listener具有相同Binder对象的服务端listener并把它删掉即可。并且它能够自动移除客户端所注册的listener。
RemoteCallbackList内部自动实现了线程同步的功能。
No29:
RemoteCallbackList不是List,它的用法是固定的
final int N = remoteCallbackList.beginBroadcast();
for(int i = 0;i<N;i++){
Object object = remoteCallbackList.getBroadcastItem(i);
if(object !=null){
//
}
}
remoteCallbackList.finishBroadcast();
No30:
客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起。
由于客户端的onServiceConnected和onServiceDisconnected方法都运行在UI线程中,所以也不可以在它们里面直接调用服务端的耗时方法。
由于服务端的方法本身就运行在服务端的Binder线程池中,所以服务端方法本身就可以执行大量耗时操作,切记不要开线程去执行异步任务。
No31:
在AIDL中进行权限验证有两种常用方法:
1.在onBind中验证:使用permission
2.在服务端的onTransact方法中进行权限验证:采用permission
No32:
ContentProvider的底层实现同样也是Binder。
创建一个自定义的ContentProvider很简单,只需要继承ContentProvider类并实现六个抽象方法即可:onCreate、query、update、insert、delete和getType。
这六个方法均运行在ContentProvider的进程中,除了onCreate由系统回调并运行在主线程里,其他五个方法均由外界回调并运行在Binder线程池中。
No33:
Android系统所提供的MediaStore功能就是文件类型的ContentProvider。
ContentProvider对底层的数据存储方式没有任何要求,我们即可以使用SQLite数据库,也可以使用普通的文件,甚至可以采用内存中的一个对象来进行数据的存储。
No34:
例:BookProvider注册:
<provider
android:name=".provider.BookProvider"
android:authorities="com.ryg.chapter_2.book.provider"
android:permission="com.ryg.PROVIDER"
android:process=":provider/>
No35:
AIDL使用流程:首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL接口中的Stub类并实现Stub中的抽象方法,在Service的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端Service,建立连接后就可以访问远程服务端的方法了。
No36:
Binder连接池工作机制:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。
No37:
Binder连接池的主要作用就是讲每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程。
No38:
RPC--远程过程调用
《android开发艺术探索》读书笔记(二)--IPC机制的更多相关文章
- Android开发艺术探索——第二章:IPC机制(上)
Android开发艺术探索--第二章:IPC机制(上) 本章主要讲解Android的IPC机制,首先介绍Android中的多进程概念以及多进程开发模式中常见的注意事项,接着介绍Android中的序列化 ...
- Android开发艺术探索——第二章:IPC机制(中)
Android开发艺术探索--第二章:IPC机制(中) 好的,我们继续来了解IPC机制,在上篇我们可能就是把理论的知识写完了,然后现在基本上是可以实战了. 一.Android中的IPC方式 本节我们开 ...
- Android开发艺术探索读书笔记——01 Activity的生命周期
http://www.cnblogs.com/csonezp/p/5121142.html 新买了一本书,<Android开发艺术探索>.这本书算是一本进阶书籍,适合有一定安卓开发基础,做 ...
- Android开发艺术探索读书笔记——进程间通信
1. 多进程使用场景 1) 应用某些模块由于特殊需求须要执行在单独进程中. 如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会由于应用程序进程crash而受影响. 2) 为加大一个应用可 ...
- android开发艺术探索读书笔记之-------view的事件分发机制
View的点击事件的分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个过程就是分发过程. 分发过程主要由以下 ...
- Android开发艺术探索学习笔记(三)
第三章 View的事件体系 3.1 View基础知识 3.1.1 什么是view View 是Android中所有控件的基类,是一种界面层的控件的一种抽象,它代表了一个控件. 3.1.2 View的 ...
- Android开发艺术探索学习笔记(十一)
第十一章 Android的线程和线程池 从用途上来说,线程分为子线程和主线程,主线程主要处理和界面相关的事情,而子线程往往用于执行耗时的操作.AsyncTask,IntentService,Hand ...
- Android开发艺术探索学习笔记(十)
第十章 Android的消息机制 面试中经常会被问到的一个问题:handler是如何在子线程和主线程中进行消息的传递的,这个问题通过了解Android的消息机制可以得到一个准确的答案. Androi ...
- Android开发艺术探索学习笔记(六)
第六章 Android的Drawable Drawable的优点:使用简单,比自定义view的成本要低:非图片类型的Drawable占用空间小,有利于减小APK安装包的大小. 6.1Drawable ...
- Android开发艺术探索学习笔记(四)
第四章 View的工作原理 4.1初识ViewRoot和DecorView ViewRoot是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成 ...
随机推荐
- python_如何定义装饰器类?
案例: 实现一个能将函数调用信息记录到日志的装饰器 需求: 把每次函数的调用时间,执行时间,调用次数写入日志 可以对被装饰函数分组,调用信息记录到不同日志 动态修改参数,比如日志格式 动态打开关闭日志 ...
- js中的监听事件总结
javascript事件与功能说明大全:http://tools.jb51.net/table/javascript_event 1.滚动条监听事件 例1:监听滚动条距离页面顶端距离 <scri ...
- js内置函数大全及基本使用方法(一)
一,常规函数 alert函数:显示一个警告对话框,包括一个OK按钮. 语法:alert("hello world"); confirm函数:显示一个确认对话框,包括OK.Cance ...
- C# 多线程复习笔记
编码的日子其实也有一段时间了,但是,作为一个客户端程序,因为自己是做游戏开发的,一直没有对线程这个概念比较模糊吧. 记录下线程的整理学习路线.原文:http://www.cnblogs.com/min ...
- 【转】DEM DTM DLG DRG DOM DSM
pasting DTM DLG DRG DOM DSM" title="[转载]DEM DTM DLG DRG DOM DSM" height="477&quo ...
- redis数据类型-散列类型
Redis数据类型 散列类型 Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他 ...
- 怎样共享windows和linux之间的文件
注:本文参考自:https://www.howtogeek.com/176471/how-to-share-files-between-windows-and-linux/,相当于是原文的翻译. 一. ...
- Linux下查看CPU、内存和硬盘信息命令
一.查看cpu信息 cat /proc/cpuinfo 相同physical id 的记录是属于同一个CPU的,对应于多核的信息. 二.查看内存的信息 cat /proc/meminfo 三.查看硬盘 ...
- 《Thinking in Java》学习笔记(三)
1>Java中的常量 使用final和static来修饰的变量称为常量,常量用大写字母表示,字母间用下划线连接. Java中定义常量有以下几种方式: interface ConstantInte ...
- 洛谷 [P2761] 软件补丁问题
并不是网络流 状压+SPFA 通过题目中的描述及数据范围可知,我们状压当前的漏洞,以每个二进制位表示是否有这个漏洞,并以状压的结果为顶点,以补丁的时间为边跑SPFA即可 #include <io ...