In my application users select picture from gallery and upload. On many devices my code works perfect but on new devices (etc: samsung S5, LG G2, Samsung S4) application crashes
Because since android kitkat, you can not get pick image local path as normal way. Please check device android version, if version < kitkat, you can use your way. If version is kitkat or later, you can try this code to get file path, then you can convert to bitmap or anything you want.
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
This code goes in your onActivityResult:
AsyncTask<Uri, Void, Bitmap> imageLoadAsyncTask = new AsyncTask<Uri, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Uri... uris) {
return getBitmapFromUri(uris[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//crop, resize, play, do whatever with the bitmap
}
};
imageLoadAsyncTask.execute(data.getData());
This is getting called from AsyncTask because sometimes the images/files might not be stored locally like images backed up on Google+ or Google Drive. As recommended in this Devbyte video, always call it on the background thread.
private Bitmap getBitmapFromUri(Uri uri){
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return bitmap;
} catch (IOException e) {
Log.e(tag, "Failed to load image.", e);
e.printStackTrace();
return null;
} finally{
try {
if (parcelFileDescriptor != null) {
parcelFileDescriptor.close();
}
} catch (IOException e) {
e.printStackTrace();
Log.e(tag, "Error closing ParcelFile Descriptor");
}
}
}
This is from the sample code for Storage Client Sample and I've tested it on Kitkat and Lollipop.
Will test on older versions and update. If anyone tests this on older version, let me know.
Update: Tested on JellyBean and it works.
in this tutorial used an util class which is handling all types of images from different sources. https://www.simplifiedcoding.net/upload-pdf-file-server-android/ you have to do just, in on onActivityResult method
String path = FilePath.getPath(this, filePath);
you will get right path, across every device and every source of app which are providing images(FilePath class will available in above tutorial link)