2012-12-13 14 views
7

Mam aplikację, w której został ustawiony widok obrazu i można go kliknąć, aby otworzyć w galerii.Udostępnianie obrazów przechowywanych w pamięci wewnętrznej

Domyślnie, używam poniższy kod, żeby dostać katalog pliku z zewnętrznej pamięci masowej do przechowywania moje JPEG:

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

Ale! Załóżmy, że pamięć zewnętrzna nie jest zamontowana lub po prostu nie istnieje (Galaxy Nexus), to nie działa. Więc napisałem instrukcję if wokół niej i otrzymałem wewnętrzny katalog pamięci podręcznej jako powrót.

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

Obrazy pokazują się dobrze w ImageView, ale nie przychodzą, gdy mój zamiar się uruchamia.

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

Galeria zostaje załadowana, ale pokazuje czarny ekran. Przypuszczalnie dlatego, że galeria nie ma dostępu do plików w katalogu pamięci podręcznej mojej aplikacji.

Jako alternatywa, próbowałem za pomocą dostawcę treści medialnych, który używa MediaStore.Images.Media.INTERNAL_CONTENT_URI, ale prowadzi to do wystąpienia błędu podczas próby Inser obraz:

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

co mam zrobić?

+0

Może mógłbym spróbować pakowania bitmapy wraz z zamiarem? Podobnie jak 'intent.putExtra (" BitmapImage ", bitmapa);'. Moje obrazy mają zwykle około 5 MB. – Maarten

+0

Możesz przechowywać obrazy w prywatnej pamięci aplikacji i przyznać ogólny dostęp tylko do odczytu, jednak wiele aplikacji, w tym niektóre z wbudowanych google, nie będzie zawracać sobie głowy sprawdzaniem, czy mają do nich dostęp, gdy poda im ścieżkę, ale po prostu załóżmy, że nie mogą i nie, nawet jeśli aplikacja posiadająca rzeczywiście przyznała globalny dostęp do odczytu. –

Odpowiedz

3

przypuszczam tutaj problemem jest to, że starają otwarty z galerii plik zapisany w prywatnej przestrzeni pamięci (getCacheDir powrócić ścieżki względnej do aplikacji i tylko aplikacja może uzyskać dostęp do ścieżki pamięci)

Jeśli nie możesz zapisać w pamięci zewnętrznej, możesz spróbować zapisać w publicznej ścieżce (ale w ten sposób Twoje pliki multimedialne mogą być modyfikowane przez każdą aplikację, a jeśli odinstalujesz aplikację, nie wyczyści ona wygenerowanych tam mediów)

Jeśli chcesz używać prywatnej pamięci wewnętrznej, możesz napisać swój ContentProvider

Edytuję, aby opublikować dostawcę treści, którego używam do realizacji tego, co powiedziałem. to mój dostawca treści (i tylko pisał odpowiednią część, czego potrzeba):

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

to trzeba w manifeście odniesienie do swojej ContentProvider, w moim przypadku było

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

a następnie używać go tak jak to

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

w moim przypadku m jest podmiotem, który przechowuje identyfikator które wskazują na db sqlite i używam klasy, która pobrać dane ponownie zapełnić obiekt (z _ mediaData), można po prostu zmienić kod do swoich potrzeb

ten sposób rozwiązałem dokładnie swój problem w mojej aplikacji

+0

To dobra odpowiedź, ale Google udostępnił "FileProvider" od tego posta. oto samouczek: http://developer.android.com/reference/android/support/v4/content/FileProvider.html – DaMachk

0

Zrozumiałem, że ten powrót nie jest potrzebny. Urządzenia z Google Play mają co najmniej 2 GB dostępnej w Environment.getExternalStorageDirectory().

Przypuszczam, że w Galaxy Nexus jest to partycja w pamięci wewnętrznej oznaczona jako zewnętrzna. Pokażę ostrzeżenie, jeśli nie jest ono dostępne.

+2

Sortuj. Galaxy Nexus z całą pewnością ma "pamięć zewnętrzną", mimo że jest wewnętrzna i nieusuwalna. Jednak na urządzeniach z usuniętym magazynem może być nieobecny; a na urządzeniach, które wykonują masową pamięć masową USB, może być niedostępna podczas podłączania do zewnętrznego komputera. –

Powiązane problemy