如何存储大量的斑点在Android内容提供商? [英] How to store large blobs in an android content provider?

查看:149
本文介绍了如何存储大量的斑点在Android内容提供商?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些较大的文件(图像和视频),我需要存储的内容提供商。 Android的文件表明...

  

如果你正在暴露字节数据的   太大,放在表本身 -   比如一个大的位图文件 -   字段暴露该数据到客户端   实际上应该包含的内容:URI   串。这是,使该场   客户访问数据文件。该   记录也应该有另一字段,   名为_data,列出了详细的   文件中的设备该文件的路径。   该字段不旨在被读   由客户端,而是由   ContentResolver的。客户端将调用   ContentResolver.openInputStream上()   用户面向字段保持该URI   为项。该ContentResolver的会   要求_data字段的   记录,而且因为它具有较高的   比客户端权限,它应该   能够直接访问该文件   并返回一个读包装的文件   到客户端。    - <一个href="http://developer.android.com/guide/topics/providers/content-providers.html#creating">http://developer.android.com/guide/topics/providers/content-providers.html#creating

我有一些很难找到一个例子。 我特别希望使用位图的背景下,一个ImageView的。 请看下面的code准code(它不工作)...

  ImageView的IV = ....
串iconUri = cursor.getString(cursor.getColumnIndex(Table.ICON));
iv.setImageURI(Uri.parse(iconUri));
 

意见/问题...

  1. 如何储存/回收的URI被正确重建? (它是文本在表格)
  2. 该setImageURI实现使用内容决心openInputStream,所以这应该工作。

     字符串模式= mUri.getScheme();
    ...
    }否则,如果(ContentResolver.SCHEME_CONTENT.equals(方案)
            || ContentResolver.SCHEME_FILE.equals(方案)){
      尝试 {
        D = Drawable.createFromStream(
                mContext.getContentResolver()。openInputStream(穆里)
                空值);
     

    - 框架/基/核心/爪哇/安卓/空间/ ImageView.java

我得到它的工作。 我参加了一个暗示从MediaStore和MediaProvider。 其中包含的数据文件被基于所述内容提供商(目录),列名,列ID和媒体类型命名。 内容解析器然后获取文件描述符像这样...

 乌里iconUri = Uri.withAppendedPath(Table.getUri(光标),Table.ICON);
ib.setImageURI(iconUri);
 

...和内容提供实物响应...

  @覆盖
公共ParcelFileDescriptor中openFile(URI URI,字符串模式){
INT的iMode = 0;
如果(mode.contains(W))的iMode | = ParcelFileDescriptor.MODE_WRITE_ONLY;
如果(mode.contains(R))的iMode | = ParcelFileDescriptor.MODE_READ_ONLY;
如果(mode.contains(+))的iMode | = ParcelFileDescriptor.MODE_APPEND;
名单&LT;字符串&GT; PSEG = uri.getPathSegments();
如果(pseg.size()3;)返回空;

尝试 {
    文件文件路径= filePathFromRecord(pseg.get(2),pseg.get(1));
    返回ParcelFileDescriptor.open(文件路径,iMode平台);
}赶上(FileNotFoundException异常E){
    e.printStackTrace();
}
返回null;
}
 

解决方案

解决方案phreed给出了底部的问题,上半年基本上是正确的。我会尽力在这里添加一些更多的细节。

当你这样做 getContentResolver()。openInputStream(...),内容解析器会去你的内容提供商,并调用它的中openFile 方法。这是怎样的中openFile 看起来<一href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/content/ContentProvider.java;h=5fb2aaec83d7f3e857ec2bdc05f4f926fde4cd2b;hb=HEAD">ContentProvider.java:

 公共ParcelFileDescriptor中openFile(URI URI,字符串模式)
     抛出FileNotFoundException异常{
 抛出新的FileNotFoundException异常(不通过供应商支持的文件在
         + URI);
}
 

因此​​,这说明这里的不支持任何文件...的错误正是源于!您可以通过覆盖中openFile 方法,在你的子类,并提供自己的实现解决这个问题。它的整洁:你在哪里你的文件会放在当任何客户端不完美的控制 openInputStream openOutputStream

code在phreed的问题样品中产生了一丝的实现可能是什么样子。这是我需要它还会创建目录和文件略作修改版本。我是新手在这个东西,所以这可能不是做事的最佳方式,但它提供了一个思路。一方面,它应该检查,如果外部存储可用。

  @覆盖
公共ParcelFileDescriptor中openFile(URI URI,字符串模式)抛出FileNotFoundException异常{
    文件根=新的文件(Environment.getExternalStorageDirectory()
            /Android/data/com.example.myapp/cache);
    root.mkdirs();
    文件路径=新的文件(根,uri.getEn codeDPATH());
    //所以,如果URI是内容://com.example.myapp/some/data.xml,
    //我们将结束访问/Android/data/com.example.myapp/cache/some/data.xml

    INT的iMode = 0;
    如果(mode.contains(W)){
            iMode平台| = ParcelFileDescriptor.MODE_WRITE_ONLY;
            如果(!path.exists()){
                尝试 {
                    path.createNewFile();
                }赶上(IOException异常E){
                    // TODO决定该怎么做呢,谁通知...
                    e.printStackTrace();
                }
            }
    }
    如果(mode.contains(R))的iMode | = ParcelFileDescriptor.MODE_READ_ONLY;
    如果(mode.contains(+))的iMode | = ParcelFileDescriptor.MODE_APPEND;

    返回ParcelFileDescriptor.open(路径,iMode平台);
}
 

I have some large files (images and video) which I need to store in a content provider. The android documentation indicates...

If you are exposing byte data that's too big to put in the table itself — such as a large bitmap file — the field that exposes the data to clients should actually contain a content: URI string. This is the field that gives clients access to the data file. The record should also have another field, named "_data" that lists the exact file path on the device for that file. This field is not intended to be read by the client, but by the ContentResolver. The client will call ContentResolver.openInputStream() on the user-facing field holding the URI for the item. The ContentResolver will request the "_data" field for that record, and because it has higher permissions than a client, it should be able to access that file directly and return a read wrapper for the file to the client. -- http://developer.android.com/guide/topics/providers/content-providers.html#creating

I am having some difficulty finding an example. In particular I wish to use the bitmap in the context an ImageView. Consider the following code quasi-code (it doesn't work)...

ImageView iv = ....
String iconUri = cursor.getString(cursor.getColumnIndex(Table.ICON));
iv.setImageURI(Uri.parse(iconUri));

Observations/Problems...

  1. How can the stored/recovered uri be reconstructed correctly? (it is text in the table)
  2. The setImageURI implementation makes use of the content resolve openInputStream so this should work.

    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/base/core/java/android/widget/ImageView.java

I got it working. I took a hint from the MediaStore and MediaProvider. The files which contain the data are named based on the content provider (directory), the column name, the row id and the media type. The content resolver then acquires the file descriptor like so...

Uri iconUri = Uri.withAppendedPath(Table.getUri(cursor), Table.ICON);
ib.setImageURI(iconUri);

...and the content provider responds in kind...

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

解决方案

The solution phreed gives in the bottom half of question is basically correct. I'll try to add some more details here.

When you do getContentResolver().openInputStream(...), content resolver will go to your content provider and call its openFile method. This is how the openFile looks in ContentProvider.java:

public ParcelFileDescriptor openFile(Uri uri, String mode)
     throws FileNotFoundException {
 throw new FileNotFoundException("No files supported by provider at "
         + uri);
}

So this explains where the "No files supported ..." error exactly comes from! You get around this by overriding openFile method in your subclass and providing your own implementation. It's neat: you get perfect control of where your files get placed when any client does openInputStream or openOutputStream.

Code sample in phreed's question gives a hint how the implementation could look like. Here's my slightly modified version which also creates directories and files as needed. I'm novice at this stuff so this might not be the optimal way of doing things, but it gives an idea. For one thing, it should probably check if external storage is available.

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

这篇关于如何存储大量的斑点在Android内容提供商?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆