Android

以下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识概括总结(如有错误欢迎指出)(侵删):
http://blog.csdn.net/luoshengyang/article/details/8923485
http://blog.csdn.net/luoshengyang/article/details/12957169

整理by Doing

        安装应用程序的时候,并不会把相应的Content Provider加载到内存中来,系统采取的是懒加载的机制,等到第一次要使用这个Content Provider的时候,系统才会把它加载到内存中来,下次再要使用这个Content Provider的时候,就可以直接返回
 
Android应用程序组件Content Provider在应用程序之间共享数据的原理
        Content Provider组件在不同应用程序之间传输数据是基于匿名共享内存机制来实现的(在应用程序进程之间以匿名共享内存的方式来传输数据效率是非常高的,因为它们之间只需要传递一个文件描述符就可以了):
        首先在第三方应用程序这一侧,当它需要访问Content Provider中的数据时,它会在本进程中创建一个CursorWindow对象,它在内部创建了一块匿名共享内存,同时,它实现了Parcel接口,因此它可以在进程间传输。接下来第三方应用程序把这个CursorWindow对象(连同它内部的匿名共享内存文件描述符)通过Binder进程间调用传输到Content Provider这一侧。这个匿名共享内存文件描述符传输到Binder驱动程序的时候,Binder驱动程序就会在目标进程(即Content Provider所在的进程)中创建另一个匿名共享文件描述符,指向前面已经创建好的匿名共享内存,因此,就实现了在两个进程中共享同一块匿名内存
        在Content Provider这一侧利用在Binder驱动程序为它创建好的这个匿名共享内存文件描述符,在本进程中创建了一个CursorWindow对象。现在,Content Provider开始要从本地中从数据库中查询第三方应用程序想要获取的数据了。Content Provider首先会创建一个SQLiteCursor对象,即SQLite数据库游标对象,它继承了AbstractWindowedCursor类,后者又继承了AbstractCursor类,而AbstractCursor类又实现了CrossProcessCursor和Cursor接口。其中,最重要的是在AbstractWindowedCursor类中,有一个成员变量mWindow,它的类型为CursorWindow,这个成员变量是通过AbstractWindowedCursor的子类SQLiteCursor的setWindow成员函数来设置的。这个SQLiteCursor对象设置好了父类AbstractWindowedCursor类的mWindow成员变量之后,它就具有传输数据的能力了,因为这个mWindow对象内部包含一块匿名共享内存。此外,这个SQLiteCursor对象的内部有两个成员变量,一个是SQLite数据库对象mDatabase,另外一个是SQLite数据库查询对象mQuery。SQLite数据库查询对象mQuery的类型为SQLiteQuery,它继承了SQLiteProgram类,后者又继承了SQLiteClosable类。SQLiteProgram类代表一个数据库存查询计划,它的成员变量mCompiledSql包含了一个已经编译好的SQL查询语句,SQLiteCursor对象就是利用这个编译好的SQL查询语句来获得数据的,但是它并不是马上就去获取数据的,而是等到需要时才去获取
        那么,要等到什么时候才会需要获取数据呢?一般来说,如果第三方应用程序在请求Content Provider返回数据时,如果指定了要返回关于这些数据的元信息时,例如数据条目的数量,那么Content Provider在把这个SQLiteCursor对象返回给第三方应用程序之前,就会去获取数据,因为只有获取了数据之后,才知道数据条目的数量是多少。SQLiteCursor对象通过调用成员变量mQuery的fillWindow成员函数来把从SQLite数据库中查询得到的数据保存其父类AbstractWindowedCursor的成员变量mWindow中去,即保存到第三方应用程序创建的这块匿名共享内存中去。如果第三方应用程序在请求Content Provider返回数据时,没有指定要返回关于这些数据的元信息,那么,就要等到第三方应用程序首次调用这个从Content Provider处返回的SQLiteCursor对象的数据获取方法时,才会真正执行从数据库存中查询数据的操作,例如调用了SQLiteCursor对象的getCount或者moveToFirst成员函数时。这是一种数据懒加载机制,需要的时候才去加载,这样就提高了数据传输过程中的效率。
        上面说到,Content Provider向第三方应用程序返回的数据实际上是一个SQLiteCursor对象,那么,这个SQLiteCursor对象是如何传输到第三方应用程序的呢?因为它本身并不是一个Binder对象,我们需要对它进行适配一下。首先,Content Provider会根据这个SQLiteCursor对象来创建一个CursorToBulkCursorAdaptor适配器对象,这个适配器对象是一个Binder对象,因此,它可以在进程间传输,同时,它实现了IBulkCursor接口。Content Provider接着就通过Binder进程间通信机制把这个CursorToBulkCursorAdaptor对象返回给第三方应用程序,第三方应用程序得到了这个CursorToBulkCursorAdaptor之后,再在本地创建一个BulkCursorToCursorAdaptor对象,这个BulkCursorToCursorAdaptor对象的继承结构和SQLiteCursor对象是一样的,不过,它没有设置父类AbstractWindowedCursor的mWindow成员变量,因此,它只可以通过它内部的CursorToBulkCursorAdaptor对象引用来访问匿名共享内存中的数据,即通过访问Content Provider这一侧的SQLiteCursor对象来访问共享数据。
 
 
Content Provider的共享数据更新通知机制
        ContentObserver类的成员变量mTransport是一个Binder对象,它是要传递给ContentService服务的,以便当ContentObserver所监控的数据发生变化时,ContentService服务可以通过这个Binder对象通知相应的ContentObserver它监控的数据发生变化了
         Android应用程序组件Content Provider中的数据更新通知机制和Android系统中的广播(Broadcast)通知机制的实现思路是相似的。然而,Content Provider中的数据监控机制与Android系统中的广播机制又有三个主要的区别:
  1. 一是前者是通过URI来把通知的发送者和接收者关联在一起的,而后者是通过Intent来关联的
  2. 二是前者的通知注册中心是由ContentService服务来扮演的,而后者是由ActivityManagerService服务来扮演的
  3. 三是前者负责接收数据更新通知的类必须要继承ContentObserver类,而后者要继承BroadcastReceiver类。
        之所以会有这些区别,是由于Content Proivder组件的数据共享功能本身就是建立在URI的基础之上的,因此专门针对URI来设计另外一套通知机制会更实用和方便,而Android系统的广播机制是一种更加通用的事件通知机制,它的适用范围会更广泛一些。
        
 
 
原文地址:https://www.cnblogs.com/Doing-what-I-love/p/5530393.html