【问题标题】:Android ContentProvider Cursor issueAndroid ContentProvider 游标问题
【发布时间】:2014-11-13 04:12:52
【问题描述】:

我正在尝试为我的应用程序编写一个内容提供程序,以允许访问我的应用程序存储在 SD 卡上的某些文件。文件的名称是其内容 URI 的哈希值,例如,content://my.app.files/test.pdf 将位于 /sdcard/data/Android/my.app/cache/MD5(my.app.files/test.pdf),其中 MD5() 是 MD5 哈希值。

我的内容提供者如下所示:

public class CacheContentProvider extends ContentProvider {
    private static final String[] COLUMNS= { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
    public static final Uri CONTENT_URI = Uri.parse("content://my.app.files/");
    private DiskCache mCache;

    @Override
    public boolean onCreate() {
        PotDroidApplication.initImageLoader(getContext());
        final ImageLoader il = ImageLoader.getInstance();
        mCache = il.getDiskCache();
        return true;
    }

    @Override
    public String getType(Uri uri) {
        final File file = getFileForUri(uri);

        final int lastDot = file.getName().lastIndexOf('.');
        if (lastDot >= 0) {
            final String extension = file.getName().substring(lastDot + 1);
            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            if (mime != null) {
                return mime;
            }
        }

        return "application/octet-stream";
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        final File f = getFileForUri(getContentUriFromUrlOrUri(uri.toString()));

        if (f.exists()) {
            return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
        }

        throw new FileNotFoundException(uri.getPath());
    }

    private File getFileForUri(Uri uri) {
        return DiskCacheUtils.findInCache(uri.toString(), mCache);
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        final File file = getFileForUri(uri);

        if (projection == null) {
            projection = COLUMNS;
        }

        String[] cols = new String[projection.length];
        Object[] values = new Object[projection.length];
        int i = 0;
        for (String col : projection) {
            if (OpenableColumns.DISPLAY_NAME.equals(col)) {
                cols[i] = OpenableColumns.DISPLAY_NAME;
                values[i++] = uri.getLastPathSegment();
            } else if (OpenableColumns.SIZE.equals(col)) {
                cols[i] = OpenableColumns.SIZE;
                values[i++] = file.length();
            }
        }
        cols = copyOf(cols, i);
        values = copyOf(values, i);
        final MatrixCursor cursor = new MatrixCursor(cols, 1);
        cursor.addRow(values);
        return cursor;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }

    public static Uri getContentUriFromUrlOrUri(String rawUrl) {
        if(rawUrl.startsWith(CONTENT_URI.toString()))
            return Uri.parse(rawUrl);
        try {
            URL url = new URL(rawUrl.replace("%20","+"));
            return Uri.parse(CONTENT_URI + url.getHost() + url.getPath());
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static String[] copyOf(String[] original, int newLength) {
        final String[] result = new String[newLength];
        System.arraycopy(original, 0, result, 0, newLength);
        return result;
    }

    private static Object[] copyOf(Object[] original, int newLength) {
        final Object[] result = new Object[newLength];
        System.arraycopy(original, 0, result, 0, newLength);
        return result;
    }

    public static class HashFileNameGenerator extends Md5FileNameGenerator {
        @Override
        public String generate(String url) {
            Uri uri = getContentUriFromUrlOrUri(url);
            if(uri == null)
                return super.generate(url);
            return super.generate(uri.toString());
        }
    }

}

Provider 似乎可以很好地解析content:// URI 并与某些应用程序共享,例如 Dropbox,也可以正常工作。但是,当我尝试与某些应用程序共享文件时,某些应用程序会抛出异常,例如 Acrobat PDF 转换器。例外情况如下:

Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
            at android.database.CursorWindow.nativeGetString(Native Method)
            at android.database.CursorWindow.getString(CursorWindow.java:434)
            at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
...

因此,显然,该应用正在寻找我通过 query() 方法返回的光标中不存在的某些列。我究竟做错了什么?我基本上是从Android原生的FileProvider中复制了query()的方法。

【问题讨论】:

  • 覆盖 MatrixCursor.getColumnIndex 并查看它需要哪些列
  • 我早该想到的。 :) 谢谢,今晚试试。
  • 或/和 getColumnIndexOrThrow
  • 无论出于何种原因,这两种方法都没有被调用。 :(还有其他想法吗?
  • 未调用? unmöglich,它怎么能读取你的光标,不知道使用什么列索引

标签: android android-contentprovider


【解决方案1】:

如果您在 ContentProvider 中公开媒体文件,则其 query() 方法应返回 MediaStore.MediaColumns

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多