【问题标题】:openContactPhotoInputStream causes “java.lang.IllegalStateException: get field slot from row 0 col 0 failed”openContactPhotoInputStream 导致“java.lang.IllegalStateException: get field slot from row 0 col 0 failed”
【发布时间】:2014-01-22 19:32:03
【问题描述】:

背景

我正在尝试检查特定联系人的联系人图像是否存在(稍后才能真正获取它,很久以后)。查询应尽可能少,并避免不必要的内存使用。

我发现这可能无法使用正常方式,所以现在我正在使用:

final Uri lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, contactKey);
final Cursor contactCur = mContentResolver.query(lookupUri, new String[] { ContactsContract.Contacts._ID },
        null, null, null);
if (contactCur == null)
    return false;
contactCur.moveToFirst();
long contactId = 0;
if (contactCur.getCount() != 0)
    contactId = contactCur.getLong(contactCur.getColumnIndex(ContactsContract.Contacts._ID));
contactCur.close();
if (contactId == 0)
    return false;
final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);

final InputStream inputStream;
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH)
    inputStream = ContactsContract.Contacts.openContactPhotoInputStream(mContext.getContentResolver(),
            contactUri, bigPicture);
else
    inputStream = ContactsContract.Contacts.openContactPhotoInputStream(mContext.getContentResolver(),
            contactUri);
if (inputStream != null) {
    IOUtils.closeQuietly(inputStream);
    return true;
}
return false;

问题

似乎在极少数情况下,设备会向我返回以下异常:

java.lang.IllegalStateException:从行 0 col 0 获取字段槽 在 android.database.CursorWindow.getBlob_native 失败(本机方法) 在 android.database.CursorWindow.getBlob(CursorWindow.java:288) 在 android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:35) 在 android.database.CursorWrapper.getBlob(CursorWrapper.java:143) 在 android.provider.ContactsContract$Contacts.openContactPhotoInputStream(ContactsContract.java:1174)

事实证明,有很多关于这个问题的报告,但没有关于“openContactPhotoInputStream”功能。

从我读到的(例如here),这是因为需要读取的blob太大,但在这种情况下,我在Android的代码中遇到了这个问题......

问题

克服这个问题的最佳方法是什么?

这可能是 Android 上的错误吗?

我的猜测是,即使我使用 try-catch ,当我稍后尝试获取图像时,我也会得到同样的错误,对吧?

我该如何解决这个问题?

【问题讨论】:

    标签: android blob android-contacts illegalstateexception


    【解决方案1】:

    如何检查照片是否存在(未经测试):

    ContentResolver cr = mContext.getContentResolver();
    if (bigPicture && VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
        Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
                ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
        AssetFileDescriptor fd = null;
        try {
            fd = cr.openAssetFileDescriptor(displayPhotoUri, "r");
        } catch (FileNotFoundException e) {}
        if (fd != null) {
            try {
                fd.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return true;
        }
    }
    
    Uri photoUri = Uri.withAppendedPath(contactUri,
            ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
    Cursor cursor = cr.query(photoUri, new String[] {BaseColumns._ID},
            ContactsContract.Contacts.Photo.PHOTO + " IS NOT NULL", null, null);
    if (cursor == null) {
        return false;
    }
    try {
        return cursor.moveToFirst();
    } finally {
        cursor.close();
    }
    

    这里是 openContactPhotoInputStream() 方法的修改版本,它应该能够毫无问题地加载大小接近 1 MB 的照片缩略图(再次未经测试):

    public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
            boolean preferHighres) {
        if (preferHighres && VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
            Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
                    ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
            try {
                return cr.openAssetFileDescriptor(displayPhotoUri, "r").createInputStream();
            } catch (IOException e) {}
        }
        Uri photoUri = Uri.withAppendedPath(contactUri,
                ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
        try {
            return cr.openAssetFileDescriptor(displayPhotoUri, "r").createInputStream();
        } catch (IOException e) {}
        return null;
    }
    

    这应该会导致ContactsProvider 读取缩略图BLOB 到共享内存,并发送一个指向它的AssetFileDescriptor,我们可以从中直接打开一个InputStream

    【讨论】:

    • 是否使用“DISPLAY_PHOTO”打开文件描述符与使用 inputStream 的方法相同?它是否以某种方式避免了我提到的问题?是否可以在不打开任何文件的情况下进行查询?
    • @androiddeveloper:这段代码是从openContactPhotoInputStream()方法实现中复制的,但修改为只查询PHOTO列中是否存在数据,而不是查询照片BLOB本身。在高分辨率照片文件查询的情况下,它还避免了从AssetFileDescriptor 不必要地打开InputSteam。由于这段代码没有从Cursor 读取大的BLOB,它应该可以解决您遇到的问题。
    • 我明白了。遗憾的是,这是一个非常罕见的错误,所以我无法知道它是否在很长一段时间后修复了任何问题。希望我记得勾选它,如果它是正确的。感谢您的时间。现在,您将获得赞成票而不是打勾... :)
    • @androiddeveloper:您可以从代码本身看到它解决了您的问题:) 异常是由openContactPhotoInputStream() 方法在Cursor 上调用getBlob() 引起的,您可以看到在我的解决方案中,我没有打电话给getBlob()。代码可能还有其他问题,因为它没有经过测试,但这个问题应该已经解决了。但是如果你想在接受之前等待和测试也没关系。
    • 但是之后我可以阅读照片吗?正如我所写的,我有两个步骤,它们之间的时间间隔很长:一个用于查询照片,一个用于获取它。尝试阅读照片时不会出现此异常吗?
    猜你喜欢
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-27
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    相关资源
    最近更新 更多