12

我有一些需要存储在内容提供者中的大文件(图片和视频)。 Android的文件表明...如何在android内容提供者中存储大块?

如果你露出那 太大,放在表本身字节数据 - 如大的位图文件 - 在 场暴露的数据给客户 应实际上包含一个内容:URI 字符串。这是允许 客户端访问数据文件的字段。 记录还应该有另一个字段,名为“_data”的 ,该字段在该设备上列出该文件的确切文件路径 。 此字段不打算由客户端读取 ,而是由 ContentResolver读取。客户将拨打 ContentResolver.openInputStream() 面向用户的字段,该字段为该项目保存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)); 

的意见/问题...

  1. 如何存储/回收URI正确重建? (它是表格中的文本)
  2. 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); 
    

    --frameworks /基/核心/ 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

糟糕!我通过编辑原始文本而不是发布答案来回答我自己的问题,即“如何在Android内容提供商中存储大型斑点”。在任何情况下,简短的回答是你使用openFile和朋友描述的方式。 – phreed 2010-11-13 20:18:22

回答

11

这两个文件对象之间是否存在任何交互?解决方法phreed在问题的下半部分给出的基本上是正确的,我将尝试在此处添加更多详细信息。

当你做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方法并提供你自己的实现。它很整洁:当任何客户端使用openInputStreamopenOutputStream时,您可以完美控制文件的放置位置。

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); 
} 
+0

你好@Peteris Caune。我已经像你一样实现了openFile方法,但是我仍然没有弄清楚如何使用openFileMethod()中的ParcelFileDescriptor对象来写入我的文件(*。png),并且现在要怎么填充“_data”字段。我花了很多时间寻找一个例子或解释。谢谢 – AlexSanchez 2013-08-01 18:53:32

+0

我自己解决它,似乎字段'_data'是供应商使用的专用,所以我一直在尝试像游标中的常规字段一样提取数据。我已经注意到我需要使用'mResolver.openInputStream(resourceUri);'方法。 btw谢谢。 – AlexSanchez 2013-08-01 22:16:00

0

有虽然写文件的问题。内容提供者如何知道写入完成?

当关闭通过ContentResolver.openOutputStream()获取的OutputStream时,我希望相应的(自定义)ContentProvider执行一些自定义操作。 目前我正在使用在temporary file 上创建FileObserver,但它似乎是完成它的错误方法。 我的第一个想法是子类型方法产生的ParcelFileDescriptor,但这似乎并不适用于我。

这就是说有一些错误导致了MyParcelFileDescriptor的使用。

  • 我没有确保文件描述符不会被过早垃圾收集。
  • 我没有尝试重写最后()(文件似乎表明正在这样做,但接近()的地方似乎是正确的选择我。

底那么在ContentResolverContentProvider

+0

虽然写文件有问题。内容提供者如何知道写入完成? http://stackoverflow.com/questions/4147763/android-content-provider-custom-openfile-onclose-behavior – phreed 2010-12-14 14:07:24

+0

[文档](http://developer.android.com/reference/android/content/ContentProvider.html #openFile(android.net.Uri,%20java.lang.String))说:* ...返回的ParcelFileDescriptor由调用者拥有,所以完成后关闭它是他们的责任。也就是说,这个方法的实现应该为每个调用创建一个新的ParcelFileDescriptor。*因此,您不必担心关闭ParcelFileDescriptor实例。 – 2012-12-18 03:59:05

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); 
} 

Click here for detail

相关问题