2012-12-13 213 views
7

我有一個應用程序,其中設置了一個ImageView,並且可以單擊該應用程序以在庫中打開。共享存儲在內部存儲器中的圖像

默認情況下,我用下面的代碼從外部存儲器獲取文件目錄來存儲我的JPEG文件:

File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp"); 

但是!假設外部存儲沒有安裝或根本不存在(Galaxy Nexus),這不起作用。所以我寫了一個if語句,並獲得內部緩存目錄作爲回退。

String state = Environment.getExternalStorageState() 
if(Environment.MEDIA_MOUNTED.equals(state)){ 
    File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");  
}else{ 
    context.getCacheDir(); 
} 

的圖像顯示了罰款,在ImageView的,但是當我的意圖啓動不來通過。

Intent intent = new Intent();    
intent.setAction(android.content.Intent.ACTION_VIEW); 
intent.setDataAndType(Uri.fromFile(imgFile), "image/jpeg"); 
startActivity(intent); 

畫廊獲取加載,但顯示黑屏。據推測,因爲畫廊無法訪問我的應用程序的緩存目錄中的文件。

作爲替代方案,我嘗試使用,使用MediaStore.Images.Media.INTERNAL_CONTENT_URI媒體內容提供商,但這種努力inser圖像時會導致錯誤:

java.lang.UnsupportedOperationException: Writing to internal storage is not supported. 

我該怎麼辦?

+0

或許我可以嘗試的意圖沿着封裝位圖正好解決了你的問題?像'intent.putExtra(「BitmapImage」,位圖);'。我的圖像通常約爲5MB。 – Maarten

+0

您可以將圖像存儲在應用程序的私人存儲空間中,並授予一般READ ONLY訪問權限,但許多應用程序(包括某些Google內置插件)不會檢查在將路徑交給他們時是否可以訪問這些應用程序,假定它們不能和失敗,即使擁有的應用程序實際上已授予全局讀取訪問權限。 –

回答

3

我想這裏的問題是,你正在試圖與庫保存在內存中的私人空間的文件打開(getCacheDir一個相對路徑返回到應用程序,只有您的應用程序可以訪問存儲路徑)

如果您不能保存在外部存儲器中,則可以嘗試保存在公共路徑中(但這樣,您的媒體文件可以被每個應用程序操縱,如果您卸載應用程序,則不會清除您保存在那裏的生成媒體)

如果你想使用私人內存,你可以寫你的ContentProvider

我編輯發佈一個內容提供商,我用它來表達我所說的話。 這是我的內容提供商(我剛剛發佈你所需要的相關部分):

public class MediaContentProvider extends ContentProvider { 
private static final String TAG = "MediaContentProvider"; 

// name for the provider class 
public static final String AUTHORITY = "com.way.srl.HandyWay.contentproviders.media"; 

private MediaData _mediaData; 

// UriMatcher used to match against incoming requests 
private UriMatcher _uriMatcher; 

@Override 
public int delete(Uri uri, String selection, String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
} 

@Override 
public String getType(Uri uri) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public Uri insert(Uri uri, ContentValues values) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public boolean onCreate() { 
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 

    // Add a URI to the matcher which will match against the form 
    // 'content://com.stephendnicholas.gmailattach.provider/*' 
    // and return 1 in the case that the incoming Uri matches this pattern 
    _uriMatcher.addURI(AUTHORITY, "*", 1); 

    return true; 
} 

@Override 
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
} 

@Override 
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 

    Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment()); 

    // Check incoming Uri against the matcher 
    switch (_uriMatcher.match(uri)) { 

    // If it returns 1 - then it matches the Uri defined in onCreate 
     case 1: 

      // The desired file name is specified by the last segment of the 
      // path 
      // E.g. 
      // 'content://com.stephendnicholas.gmailattach.provider/Test.txt' 
      // Take this and build the path to the file 
      // String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment(); 
      Integer mediaID = Integer.valueOf(uri.getLastPathSegment()); 

      if (_mediaData == null) { 
       _mediaData = new MediaData(); 
      } 
      Media m = _mediaData.get(mediaID); 

      // Create & return a ParcelFileDescriptor pointing to the file 
      // Note: I don't care what mode they ask for - they're only getting 
      // read only 
      ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(m.filePath), ParcelFileDescriptor.MODE_READ_ONLY); 
      return pfd; 

      // Otherwise unrecognised Uri 
     default: 
      Log.v(TAG, "Unsupported uri: '" + uri + "'."); 
      throw new FileNotFoundException("Unsupported uri: " + uri.toString()); 
    } 
} 

,那麼你在清單中需要參考您的ContentProvider,在我的情況下,它是

<provider 
     android:name=".contentproviders.MediaContentProvider" 
     android:authorities="com.way.srl.HandyWay.contentproviders.media" > 
    </provider> 

,然後使用這樣的

Intent intent = new Intent(); 
intent.setAction(Intent.ACTION_VIEW); 
intent.setDataAndType(Uri.parse("content://" + MediaContentProvider.AUTHORITY + "/" + m.id), "image/jpg"); 
在我當m

是存儲指向一個SQLite數據庫的ID的實體,我使用獲取數據類再次填充對象(_ mediaData),你可以更改代碼以滿足您的需求

這樣,我在我的應用程序

+0

這是一個很好的答案,但Google自從這篇文章提供了一個'FileProvider'。這裏有一個教程:http://developer.android.com/reference/android/support/v4/content/FileProvider.html – DaMachk

0

我知道這個回退是不需要的。有Google Play的設備保證在Environment.getExternalStorageDirectory()中至少有2 GB可用。

我想在Galaxy Nexus上這是內部存儲器上的一個分區,標記爲外部分區。如果它不可用,我只會顯示警告。

+2

排序Galaxy Nexus絕對有一個「外部存儲」,即使它是內部的和不可移動的。但是,在移除了存儲的設備上,它可能不存在;而在使用USB大容量存儲的設備上,它可以在安裝到外部計算機時不可用。 –

相關問題