企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
1. 客户端query关键点 按以前的分析习惯,碰到Binder调用时会马上转入服务端(即Bn端)去分析,但是这个思路在query函数中行不通。为什么?来看IContentProvider Bp端的query函数,它定义在ContentProviderProxy中,代码如下: **ContentProviderNative.java::ContentProviderProxy.query** ~~~ public Cursor query(Uri url, String[] projection,String selection, String[] selectionArgs, String sortOrder) throws RemoteException { //①构造一个BulkCursorToCursorAdaptor对象 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); Parceldata = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); ......//将参数打包到data请求包中 //②adaptor.getObserver()返回一个IContentObserver类型的对象,把它 //也打包到data请求包中。ContentObserver相关的知识留到第8章再分析 data.writeStrongBinder(adaptor.getObserver().asBinder()); //发送请求给远端的Bn端 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); //③从回复包中得到一个IBulkCursor类型的对象 IBulkCursor bulkCursor = BulkCursorNative.asInterface(reply.readStrongBinder()); if(bulkCursor != null) { int rowCount = reply.readInt(); int idColumnPosition = reply.readInt(); boolean wantsAllOnMoveCalls = reply.readInt() != 0; //④调用adaptor的initialize函数 adaptor.initialize(bulkCursor, rowCount, idColumnPosition, wantsAllOnMoveCalls); } ...... return adaptor; } ...... finally { data.recycle(); reply.recycle(); } } ~~~ 从以上代码中可发现,ContentProviderProxy query函数中还大有文章,其中一共列出了4个关键点。最令人头疼的是其中新出现的两个类BulkCursorToCursorAdaptor和IBulkCursor。此处不必急于分析它们。 我们再到服务端去提取query函数的关键点。 2. 服务端query关键点 根据第2章对Binder的介绍,客户端发来的请求先在Bn端的onTransact中得到处理,代码如下: **ContentProviderNative.java::onTransact** ~~~ public boolean onTransact(int code, Parcel data, Parcelreply, int flags) throws RemoteException { try { switch (code) { case QUERY_TRANSACTION://处理query请求 { data.enforceInterface(IContentProvider.descriptor); Uri url = Uri.CREATOR.createFromParcel(data); ......//从请求包中提取参数 //⑤创建ContentObserver Binder通信的Bp端 IContentObserver observer = IContentObserver.Stub.asInterface( data.readStrongBinder()); //⑥调用MediaProvider实现的query函数。Cursor是一个接口类,那么变量 //cursor的真实类型是什么? Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder); if(cursor != null) { //⑦创建一个CursorToBulkCursorAdaptor类型的对象 CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor( cursor,observer, getProviderName()); final IBinder binder = adaptor.asBinder(); //⑧返回结果集所含记录项的条数,这个函数看起来极不起眼,但却非常为关键 final int count = adaptor.count(); //返回名为"_id"的列在结果集中的索引位置,该列由数据库在创建表时自动添加 final int index = BulkCursorToCursorAdaptor.findRowIdColumnIndex( adaptor.getColumnNames()); //wantsAllOnMoveCalls一般为false,读者阅读完本章后再自行分析它 final boolean wantsAllOnMoveCalls = adaptor.getWantsAllOnMoveCalls(); reply.writeNoException(); //将binder的信息写到reply回复包中 reply.writeStrongBinder(binder); reply.writeInt(count);//将结果集包含的记录项行数返回给客户端 reply.writeInt(index); reply.writeInt(wantsAllOnMoveCalls ? 1 : 0); }...... return true; }......//其他情况处理 ...... } ~~~ 和客户端对应,服务端的query处理也比较复杂,其中的拦路虎仍是新出现的几种数据类型。 在扫清这些拦路虎之前,应先把客户端和服务端query调用的关键点总结一下。 3. 提取query关键点总结 我们提取query两端的调用关键点,如图7-5所示。 :-: ![](http://img.blog.csdn.net/20150803130916561?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图7-5 query调用关键点示意 再来总结一下前面提到的几个拦路虎,它们分别是: - 客户端创建的BulkCursorToCursorAdaptor、从服务端query后返回的IBulkCursor。 - 服务端创建的CursorToCursorAdaptor,以及从子类query函数返回的Cursor。 从名字上看,这几个类都和Cursor有关,所以有必要先搞清MediaProviderquery返回的Cursor到底是什么。 * * * * * **注意**:图7-5借用了UML的序列图来展示query调用顺序,其中ContentProvider框和MediaProviderer框代表同一个对象。另外,图7-5中的调用函数编号并不完全对应代码中的关键函数调用编号。 * * * * *