我有一些大文件(图片和视频)需要存储在内容提供商中。 android文档表明......
如果您正在公开字节数据 太大了,无法放入桌子本身 - 比如一个大的位图文件 - 将数据公开给客户端的字段 实际上应该包含一个内容:URI 串。这是给出的领域 客户端访问数据文件。该 记录还应该有另一个字段, 名为“_data”,列出确切的 设备上该文件的文件路径。 此字段无意阅读 由客户,但由 ContentResolver的。客户会打电话 ContentResolver.openInputStream()on 持有URI的面向用户的字段 对于该项目。 ContentResolver会 请求“_data”字段 记录,因为它有更高 权限比客户端,它应该 能够直接访问该文件 并返回该文件的读包装器 给客户。 - http://developer.android.com/guide/topics/providers/content-providers.html#creating
我很难找到一个例子。 特别是我希望在ImageView的上下文中使用位图。 考虑以下代码准代码(它不起作用)......
ImageView iv = ....
String iconUri = cursor.getString(cursor.getColumnIndex(Table.ICON));
iv.setImageURI(Uri.parse(iconUri));
观测/问题...
setImageURI实现使用内容解析openInputStream,因此这应该有效。
String scheme = mUri.getScheme();
...
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
try {
d = Drawable.createFromStream(
mContext.getContentResolver().openInputStream(mUri),
null);
- 框架/碱/核心/ JAVA /机器人/插件/ ImageView.java
我得到了它的工作。 我从MediaStore和MediaProvider中提取了一些提示。 包含数据的文件根据内容提供者(目录),列名,行ID和媒体类型命名。 然后内容解析器获取文件描述符,如此...
Uri iconUri = Uri.withAppendedPath(Table.getUri(cursor), Table.ICON);
ib.setImageURI(iconUri);
......内容提供商以实物回应......
@Override
public ParcelFileDescriptor openFile (Uri uri, String mode) {
int imode = 0;
if (mode.contains("w")) imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;
List<String> pseg = uri.getPathSegments();
if (pseg.size() < 3) return null;
try {
File filePath = filePathFromRecord(pseg.get(2), pseg.get(1));
return ParcelFileDescriptor.open(filePath, imode);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
答案 0 :(得分:12)
解决方案在下半部分提出的问题基本上是正确的。我将尝试在此处添加更多详细信息。
执行getContentResolver().openInputStream(...)
后,内容解析程序将转到您的内容提供商并调用其openFile
方法。这就是openFile
在ContentProvider.java中的显示方式:
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
}
因此,这解释了“无文件支持...”错误的确切来源!您可以通过覆盖子类中的openFile
方法并提供自己的实现来解决这个问题。它很简洁:当任何客户端openInputStream
或openOutputStream
时,您可以完美控制文件的放置位置。
phreed问题中的代码示例给出了一个提示如何实现的样子。这是我的略微修改版本,它还根据需要创建目录和文件。我是这些东西的新手,所以这可能不是最好的做事方式,但它提出了一个想法。首先,它应该检查外部存储是否可用。
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File root = new File(Environment.getExternalStorageDirectory(),
"/Android/data/com.example.myapp/cache");
root.mkdirs();
File path = new File(root, uri.getEncodedPath());
// So, if the uri was content://com.example.myapp/some/data.xml,
// we'll end up accessing /Android/data/com.example.myapp/cache/some/data.xml
int imode = 0;
if (mode.contains("w")) {
imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
if (!path.exists()) {
try {
path.createNewFile();
} catch (IOException e) {
// TODO decide what to do about it, whom to notify...
e.printStackTrace();
}
}
}
if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;
return ParcelFileDescriptor.open(path, imode);
}
答案 1 :(得分:1)
Android提供了帮助方法openFileHelper(),它使得实现openFile()方法变得非常容易。要使用此方法,您只需在名为“_data”的列中提供文件的位置。
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (URI_MATCHER.match(uri) != PHOTO_ID) {
throw new IllegalArgumentException
("URI invalid. Use an id-based URI only.");
}
return openFileHelper(uri, mode);
}
答案 2 :(得分:0)
虽然写文件有问题。内容提供商如何知道写入是否已完成?
关闭通过ContentResolver.openOutputStream()获得的OutputStream时,我希望相应的(自定义)ContentProvider执行一些自定义操作。 目前我正在使用FileObserver创建temporary file 但这似乎是完成它的错误方法。 我的第一个想法是对ParcelFileDescriptor方法生成的ContentProvider.openFile()进行子类型,但这似乎对我不起作用。
据说有一些错误导致了MyParcelFileDescriptor的使用。
最重要的是,ContentResolver看到的文件对象与ContentProvider的文件对象之间是否存在任何交互?