【发布时间】: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