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

相關問題