Provider中查询的一个Cursor对象问题

来源:互联网 发布:keynote在windows播放 编辑:程序博客网 时间:2024/06/11 21:59
文章转自:http://archive.cnblogs.com/a/1984501/

昨天写一个provider的时候出现了如下问题:

  写完之后在同一个进程内使用provider完全没有问题,但是一旦到其他进程(另一个apk)里使用的时候就会报错

E/DatabaseUtils( 339): Writing exception to parcel
E
/DatabaseUtils( 339): java.lang.UnsupportedOperationException: Only CrossProcessCursor cursors are supported across process for now
E
/DatabaseUtils( 339): at android.database.CursorToBulkCursorAdaptor.<init>(CursorToBulkCursorAdaptor.java:97)
E
/DatabaseUtils( 339): at android.content.ContentProvider$Transport.bulkQuery(ContentProvider.java:122)
E
/DatabaseUtils( 339): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:98)
E
/DatabaseUtils( 339): at android.os.Binder.execTransact(Binder.java:287)
E
/DatabaseUtils( 339): at dalvik.system.NativeStart.run(Native Method)
E
/DatabaseUtils( 339): Caused by: java.lang.ClassCastException: android.content.ContentResolver$CursorWrapperInner
E
/DatabaseUtils( 339): at android.database.CursorToBulkCursorAdaptor.<init>(CursorToBulkCursorAdaptor.java:81)

这就奇怪了,ContentProvider不就是问了跨进程才出现的啊。现在已跨进程就出问题。。。。那不就相当与没用了。

provider的query方法里面大概是这样写的

String whereInext = "";
if(number.indexOf("1") >= 0 || number.indexOf("0") >= 0){
//search the contacts directly,no need to get the where at all
return null ;
}
else {
whereInext
= this.getPinYinWhere(number);
}

return db.query(TABLE_CONTACT_INDEX, null, whereInext, null, null, null , null);

看 上去好像没错。。。返回的也是一个Cursor对象。。。其实不然。。。代码稍作修改就行了,正确的代码如下:

String whereInext = "";
if(number.indexOf("1") >= 0 || number.indexOf("0") >= 0){
//search the contacts directly,no need to get the where at all
return null ;
}
else {
whereInext
= this.getPinYinWhere(number);
}

SQLiteQueryBuilder sqlBuilder
= new SQLiteQueryBuilder();
sqlBuilder.setTables(TABLE_CONTACT_INDEX);
Cursor cursor
= sqlBuilder.query(db, null, whereInext, null , null , null , null);
Log.d(
"cx","--------number is-------"+number+"-----where from number is-----"+whereInext);

return cursor;

同样都是返回的Cursor对象。。。为什么上一种方法就会出问题呢。。

其实是这样的:

      这就是java的多态,返回的都是一个Cursor对象。。。这就是为什么向下转型是不安全的。。。

      provider将cursor跨进程传递时将会强制向下转换为CrossProcessCursor类型。。。。

      就在这时候,只有第二种方法中返回的cursor原始的类型 is a CrossProcessCursor,然而第一种方法返回的curso对象而不是

      所以在这时候,第一种方法强制类型转换会报错。。。。第二种方法则没有问题,可以转换后跨进程传递!

注意1按照作者的意思第一种方式db.query返回的cursor不是个CrossProcessCursor,所以出错。但是我在2.2中测试来看它返回的是CrossProcessCursor。之后查阅2.2中SQLiteDatabase的源码,它返回的是SQLiteCursor,SQLiteCursor继承于AbstractWindowedCursor,而AbstractWindowedCursor又继承于AbstractCursor,而AbstractCursor又是实现了CrossProcessCursor。它和测试结果相符合。作者的Android可能是更早期的版本,才引起他所说的问题。

另外我才android4.0源码中看到无论SQLiteDatabase还是SQLiteQueryBuilder都是调用SQLiteDatabaserawQueryWithFactory()方法来进行查询的,且返回类型都是声明为Cursor.

注意2:ContentProvider在进程中传递Cursor对象,需要将其转化CursorToBulkCursorAdaptor。(具体可以参照源码ContentProviderNative的bulkQuery函数)

但是其实我通过ContentResolver最后查询返回所得的Cursor对象并不是CursorToBulkCursorAdaptor

原创粉丝点击