Sharing images that are stored on internal memory
I have an application in which an ImageView is set and can be clicked to be opened in the gallery.
By default, I use the following code to get a file directory from the external storage to store my jpegs:
File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");
But! Suppose the external storage is not mounted or simply does not exist (Galaxy Nexus), this doesn't work. So I wrote an if-statement around it and get the internal cache dir as a fall back.
String state = Environment.getExternalStorageState()
if(Environment.MEDIA_MOUNTED.equals(state)){
File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");
}else{
context.getCacheDir();
}
The images show up fine in the ImageView, but don't come through when my intent launches.
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(imgFile), "image/jpeg");
startActivity(intent);
The gallery gets loaded, but shows a black screen. Presumably because the gallery has no access to files in the cache dir of my app.
As an alternative, I tried using the media content provider that uses MediaStore.Images.Media.INTERNAL_CONTENT_URI
, but this leads to an error when trying to inser the image:
java.lang.UnsupportedOperationException: Writing to internal storage is not supported.
What should I do?
i suppose the problem here is that you are trying open with the gallery a file saved in a private space of memory (getCacheDir return a path relative to your application and only your application can access that memory path)
If you can't save in external memory, you can try to save in a public path (but that way your media files can be manipulated by every app and if you uninstall your application it doesn't clean generated media that you saved there)
If you want to use private internal memory, you can write your ContentProvider
i edit to post a content provider i use to acomplish what i said. this is my content provider (i just posted the relevant part you need):
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());
}
}
then you need in the manifest the reference to your contentprovider, in my case it was
<provider
android:name=".contentproviders.MediaContentProvider"
android:authorities="com.way.srl.HandyWay.contentproviders.media" >
</provider>
and then use it like this
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("content://" + MediaContentProvider.AUTHORITY + "/" + m.id), "image/jpg");
in my case m is an entity that store an id that point to a sqlite db and i use a class that fetch data to populate again the object (with _mediaData), you can just change the code to fit your needs
this way i solved exactly your problem in my application
I have understood that this fallback is not needed. Devices that have Google Play are guaranteed to have at least 2 GB available in Environment.getExternalStorageDirectory()
.
I suppose in the Galaxy Nexus this is a partition on the internal memory marked as external. I'll just show a warning if it is not available.
链接地址: http://www.djcxy.com/p/11564.html上一篇: Windows Phone 8:以混合C#/ C ++监视内存使用情况
下一篇: 共享存储在内部存储器中的图像