J'essaie d'obtenir une image de l'application de la galerie à partir de l'un des dossiers des photos synchronisées avec Google+. Après la sélection de l'image, l'Uri est renvoyé correctement. Mais lorsque j'essaie d'obtenir le chemin d'accès réel de cette image sur le périphérique de stockage afin de pouvoir l'utiliser, le système se bloque. Le problème semble concerner spécifiquement le fournisseur de contenu picasa .
Testé sur Nexus S et Nexus 7, ainsi que sur d’autres appareils.
E/AndroidRuntime (14572): Java.lang.RuntimeException: échec lors de la livraison du résultat ResultInfo {who = null, demande = 1, résultat = -1, data = Intent {date = content: //com.google.Android. gallery3d.provider/picasa/item/5427003652908228690}}
Ici, le champ de données semble passer correctement l'Uri, mais lorsque j'essaie d'extraire l'emplacement de l'image, il se bloque avec l'erreur suivante.
W/GalleryProvider (14381): colonne non prise en charge: _data
Il semble que le fournisseur de contenu pour les albums Picasa ne possède pas de champ _data.
Le code pour obtenir l'emplacement est:
// imageUri est l'URI d'en haut . String [] proj = {MediaStore.Images.Media.DATA}; Curseur curseur = context.getContentResolver (). requête (imageUri, proj, null, null, null); int index_colonne = cursor.getColumnIndexOrThrow (MediaStore.Images.Media.DATA) cursor.close ();
Les seules colonnes qui semblent être prises en charge pour cette image sont les suivantes: [Compte_utilisateur, id_photo, _nom_écran, _size, type_mime, prise de données, latitude, longitude, orientation]
Comment pouvons-nous obtenir l'emplacement réel de cette image. Et si nous ne sommes pas censés travailler avec cette image, ces images ne doivent pas être montrées à l'utilisateur en premier lieu.
L'intention de lancer l'application de la galerie est:
Intention intention = new Intent (); Intent.setType ("image /*"); Intent.setAction (Intent.ACTION_GET_CONTENT);
Après de nombreuses recherches, j’ai estimé qu’il y avait trop de solutions de contournement pour faire quelque chose qui semble être assez simple. J'ai donc écrit une petite bibliothèque qui traite tous les problèmes complexes et fonctionne pour tous les scénarios possibles auxquels je peux penser. Essayez-le et voyez si cela aide.
http://techdroid.kbeanie.com/2013/03/easy-image-chooser-library-for-Android.html
Ceci est une implémentation initiale. Bien qu'il gère presque toutes les situations, il pourrait y avoir quelques bugs. Si vous utilisez cette bibliothèque, merci de me faire part de vos commentaires et de voir si cela pourrait être amélioré.
J'ai perdu maintenant beaucoup d'heures et maintenant j'ai trouvé une solution qui fonctionne dans tous les cas sans téléchargement magique dans des threads spéciaux ou quelque chose du genre. La méthode suivante renvoie un flux à partir du contenu sélectionné par l'utilisateur, qui fonctionne avec tout ce qui se trouve dans la nature.
FileInputStream getSourceStream(Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
ParcelFileDescriptor parcelFileDescriptor =
mContext.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
} else {
out = (FileInputStream) mContext.getContentResolver().openInputStream(u);
}
return out;
}
J'ai rencontré le même problème il y a un an .. Je vous montre ma solution (le code est assez confus, veuillez le refactoriser) . Donc, vous avez l'URI de l'image qui est retourné de la galerie:
ImageInfo getImage(URI imageUri) {
ImageInfo result = null;
final String[] cursorColumns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION};
// some devices (OS versions return an URI of com.Android instead of com.google.Android
if (imageUri.toString().startsWith("content://com.Android.gallery3d.provider")) {
// use the com.google provider, not the com.Android provider.
imageUri = Uri.parse(imageUri.toString().replace("com.Android.gallery3d","com.google.Android.gallery3d"));
}
Cursor cursor = App.getContext().getContentResolver().query(imageUri, cursorColumns, null, null, null);
if (cursor != null) {
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
int orientationColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);
cursor.moveToFirst();
// if it is a picasa image on newer devices with OS 3.0 and up
if (imageUri.toString().startsWith("content://com.google.Android.gallery3d")) {
result = new ImageInfo(downloadImage(imageUri), "0");
} else { // it is a regular local image file
result = new ImageInfo(cursor.getString(dataColumnIndex), cursor.getString(orientationColumnIndex));
}
cursor.close();
} else {
result = new ImageInfo(downloadImage(imageUri), "0");
}
return result;
}
Et maintenant, nous avons besoin d'une fonction pour télécharger l'image:
private String downloadImage(URI imageUri) {
File cacheDir;
// if the device has an SD card
if (Android.os.Environment.getExternalStorageState().equals(Android.os.Environment.MEDIA_MOUNTED)) {
cacheDir = new File(Android.os.Environment.getExternalStorageDirectory(),".OCFL311");
} else {
// it does not have an SD card
cacheDir = App.getContext().getCacheDir();
}
if(!cacheDir.exists()) cacheDir.mkdirs();
File f = new File(cacheDir, PUT_HERE_FILE_NAME_TO_STORE_IMAGE);
try {
InputStream is = null;
if (imageUri.toString().startsWith("content://com.google.Android.gallery3d")) {
is = App.getContext().getContentResolver().openInputStream(imageUri);
} else {
is = new URL(imageUri.toString()).openStream();
}
OutputStream os = new FileOutputStream(f);
Utils.InputToOutputStream(is, os);
return f.getAbsolutePath();
} catch (Exception ex) {
Log.d(this.getClass().getName(), "Exception: " + ex.getMessage());
// something went wrong
ex.printStackTrace();
return null;
}
}
ImageInfo est ma classe pour stocker le chemin d'accès à l'image et son orientation.
public static class ImageInfo {
public final String filePath;
public final String imageOrientation;
public ImageInfo(String filePath, String imageOrientation) {
this.filePath = filePath;
if (imageOrientation == null) imageOrientation = "0";
this.imageOrientation = imageOrientation;
}
}
Sur la base de la réponse @drindt, les codes ci-dessous donnent le chemin temporaire téléchargé File
à partir du fichier synchronisé mais non intégré au périphérique Google Photo.
@SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {
// Google photo uri example
// content://com.google.Android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919
if ("content".equalsIgnoreCase(uri.getScheme())) {
String result = getDataColumn(context, uri, null, null); //
if (TextUtils.isEmpty(result))
if (uri.getAuthority().contains("com.google.Android")) {
try {
File localFile = createImageFile(context, null);
FileInputStream remoteFile = getSourceStream(context, uri);
if(copyToFile(remoteFile, localFile))
result = localFile.getAbsolutePath();
remoteFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
// 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.
*/
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 column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* Copy data from a source stream to destFile.
* Return true if succeed, return false if failed.
*/
private static boolean copyToFile(InputStream inputStream, File destFile) {
if (inputStream == null || destFile == null) return false;
try {
OutputStream out = new FileOutputStream(destFile);
try {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} finally {
out.close();
}
return true;
} catch (IOException e) {
return false;
}
}
public static String getTimestamp() {
try {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
} catch (RuntimeException e) {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
}
}
public static File createImageFile(Context context, String imageFileName) throws IOException {
if (TextUtils.isEmpty(imageFileName))
imageFileName = getTimestamp(); // make random filename if you want.
final File root;
imageFileName = imageFileName;
root = context.getExternalCacheDir();
if (root != null && !root.exists())
root.mkdirs();
return new File(root, imageFileName);
}
public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = null;
if (parcelFileDescriptor != null) {
fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
}
} else {
out = (FileInputStream) context.getContentResolver().openInputStream(u);
}
return out;
}
Le truc ci-dessous a fonctionné pour moi. Ce que je fais ici est de savoir s’il existe une URL d’autorité dans l’URI, puis je crée une image temporaire en utilisant le code ci-dessous et renvoie l’URI de contenu de la même.
J'ai répondu pareil question ici aussi ..
public static String getImageUrlWithAuthority(Context context, Uri uri) {
InputStream is = null;
if (uri.getAuthority() != null) {
try {
is = context.getContentResolver().openInputStream(uri);
Bitmap bmp = BitmapFactory.decodeStream(is);
return writeToTempImageAndGetPathUri(context, bmp).toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
J'ai utilisé cette approche, fonctionne bien pour moi, espère que cela vous aidera.
ACTIVITYRESULT_CHOOSEPICTURE est l'int que vous utilisez pour appeler startActivity (intent, requestCode);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == ACTIVITYRESULT_CHOOSEPICTURE) {
BitmapFactory.Options options = new BitmapFactory.Options();
final InputStream ist = ontext.getContentResolver().openInputStream(intent.getData());
final Bitmap bitmap = BitmapFactory.decodeStream(ist, null, options);
ist.close();
}
}
si le code ci-dessus ne fonctionne pas, référez-vous simplement à ce lien ... il montrera le chemin
Enfin terminé avec une solution classique ... En utilisant Document.util, qui couvre toutes les autorités: -1-Inside your onActivityResult (): -
case GALLERY_CAPTURE_IMAGE_REQUEST_CODE:
String filePath = DocumentUtils.getPath(MainContainerActivity.this,data.getData();
break;
2- Créer la classe DocumentUtils: -
public class DocumentUtils {
@TargetApi(Build.VERSION_CODES.KitKat)
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
String url;
if (isGooglePhotosUri(uri)) {
url = getDataColumnWithAuthority(context, uri, null, null);
return getDataColumn(context, Uri.parse(url), null, null);
}
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 column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* Function for fixing synced folder image picking bug
*
* **/
public static String getDataColumnWithAuthority(Context context, Uri uri, String selection, String[] selectionArgs) {
Bitmap bitmap = null;
InputStream is = null;
if (uri.getAuthority()!=null){
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bmp = BitmapFactory.decodeStream(is);
return ImageLoader.getImageUri(context,bmp).toString();
}
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) {
if(uri.getAuthority()!=null)
return true;
return false;
}
}
3- Vous aurez également besoin de la fonction suivante dans ImageLoader.Java:-
public static Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}