open from content action_open_document android path uri android-4.4-kitkat

from - directory picker android



Obtener ruta real desde URI, Android KitKat nuevo marco de acceso de almacenamiento (9)

Antes de acceder a la galería nueva en KitKat, obtuve mi ruta real en una tarjeta SD con este método

Eso nunca fue confiable. No es necesario que ACTION_GET_CONTENT ACTION_PICK ACTION_GET_CONTENT ACTION_PICK solicitud ACTION_GET_CONTENT o MediaStore , o incluso tiene que representar un archivo en el sistema de archivos. El Uri podría, por ejemplo, representar una secuencia, en la que un archivo cifrado se descifra sobre la marcha.

¿Cómo podría obtener la ruta real en sdcard?

No hay ningún requisito de que haya un archivo correspondiente al Uri .

Sí, realmente necesito un camino

Luego copie el archivo de la transmisión en su propio archivo temporal y úselo. Mejor aún, solo use la transmisión de flujo directamente y evite el archivo temporal.

Cambié mi Intent.ACTION_GET_CONTENT por Intent.ACTION_PICK

Eso no ayudará a tu situación. No es necesario que una respuesta ACTION_PICK sea ​​para un Uri que tiene un archivo en el sistema de archivos que de alguna manera puede derivar mágicamente.

Antes del acceso a la nueva galería en Android 4.4 (KitKat) obtuve mi ruta real en la tarjeta SD con este método:

public String getPath(Uri uri) { String[] projection = { MediaStore.Images.Media.DATA }; Cursor cursor = managedQuery(uri, projection, null, null, null); startManagingCursor(cursor); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); }

Ahora, Intent.ACTION_GET_CONTENT devuelve datos diferentes:

Antes de:

content://media/external/images/media/62

Ahora:

content://com.android.providers.media.documents/document/image:62

¿Cómo podría obtener la ruta real en la tarjeta SD?


Aquí hay una versión actualizada de la respuesta de Paul Burke . En versiones inferiores a Android 4.4 (KitKat) no tenemos la clase DocumentsContract .

Para trabajar en las versiones debajo de KitKat crea esta clase:

public class DocumentsContract { private static final String DOCUMENT_URIS = "com.android.providers.media.documents " + "com.android.externalstorage.documents " + "com.android.providers.downloads.documents " + "com.android.providers.media.documents"; private static final String PATH_DOCUMENT = "document"; private static final String TAG = DocumentsContract.class.getSimpleName(); public static String getDocumentId(Uri documentUri) { final List<String> paths = documentUri.getPathSegments(); if (paths.size() < 2) { throw new IllegalArgumentException("Not a document: " + documentUri); } if (!PATH_DOCUMENT.equals(paths.get(0))) { throw new IllegalArgumentException("Not a document: " + documentUri); } return paths.get(1); } public static boolean isDocumentUri(Uri uri) { final List<String> paths = uri.getPathSegments(); Logger.v(TAG, "paths[" + paths + "]"); if (paths.size() < 2) { return false; } if (!PATH_DOCUMENT.equals(paths.get(0))) { return false; } return DOCUMENT_URIS.contains(uri.getAuthority()); } }


Esta respuesta se basa en su descripción algo vaga. Supongo que disparó un intento con la acción: Intent.ACTION_GET_CONTENT

Y ahora obtiene content://com.android.providers.media.documents/document/image:62 en lugar del anterior URI del proveedor de medios, ¿correcto?

En Android 4.4 (KitKat), la nueva DocumentsActivity se abre cuando se Intent.ACTION_GET_CONTENT lo que lleva a la vista de cuadrícula (o vista de lista) donde puede elegir una imagen, esto devolverá los siguientes URI al contexto de llamada (ejemplo): content://com.android.providers.media.documents/document/image:62 (estos son los URI del nuevo proveedor de documentos, abstrae los datos subyacentes al proporcionar URI de proveedor de documentos genéricos a los clientes).

Sin embargo, puede acceder tanto a la galería como a otras actividades que responden a Intent.ACTION_GET_CONTENT utilizando el cajón en DocumentsActivity (arrastre de izquierda a derecha y verá una UI de cajón con Gallery para elegir). Justo como pre KitKat.

Si aún puede elegir en la clase DocumentsActivity y necesita el URI del archivo, debería poder hacer la siguiente (advertencia ¡esto es hacky!) Query (con contentresolver): content://com.android.providers.media.documents/document/image:62 URI y lee el valor _display_name del cursor. Este es un nombre un tanto único (solo el nombre del archivo en los archivos locales) y usarlo en una selección (al consultar) a un proveedor de medios para obtener la fila correcta que corresponde a esta selección, desde aquí también puede buscar el URI del archivo.

Las formas recomendadas de acceder al proveedor de documentos se pueden encontrar aquí (obtenga un descriptor de flujo de entrada o de archivo para leer el archivo / mapa de bits):

Ejemplos de uso de documentprovider


Esto obtendrá la ruta del archivo desde MediaProvider, DownloadsProvider y ExternalStorageProvider, mientras recurre al método no oficial de ContentProvider que usted menciona.

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

Estos se toman de mi biblioteca de código abierto, aFileChooser .


Necesitamos hacer los siguientes cambios / correcciones en nuestro código de selector de galería onActivityResult () anterior para ejecutar sin problemas en Android 4.4 (KitKat) y en todas las demás versiones anteriores también.

Uri selectedImgFileUri = data.getData(); if (selectedImgFileUri == null ) { // The user has not selected any photo } try { InputStream input = mActivity.getContentResolver().openInputStream(selectedImgFileUri); mSelectedPhotoBmp = BitmapFactory.decodeStream(input); } catch (Throwable tr) { // Show message to try again }


Prueba esto:

//KITKAT i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, CHOOSE_IMAGE_REQUEST);

Use lo siguiente en onActivityResult:

Uri selectedImageURI = data.getData(); input = c.getContentResolver().openInputStream(selectedImageURI); BitmapFactory.decodeStream(input , null, opts);


Tuve exactamente el mismo problema. Necesito el nombre del archivo para poder subirlo a un sitio web.

Me funcionó, si cambié la intención de PICK. Esto fue probado en AVD para Android 4.4 y en AVD para Android 2.1.

Agrega el permiso READ_EXTERNAL_STORAGE:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Cambiar la intención:

Intent i = new Intent( Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI ); startActivityForResult(i, 66453666); /* OLD CODE Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser( intent, "Select Image" ), 66453666 ); */

No tuve que cambiar mi código para obtener la ruta real:

// Convert the image URI to the direct file system path of the image file public String mf_szGetRealPathFromURI(final Context context, final Uri ac_Uri ) { String result = ""; boolean isok = false; Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = context.getContentResolver().query(ac_Uri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); result = cursor.getString(column_index); isok = true; } finally { if (cursor != null) { cursor.close(); } } return isok ? result : ""; }


la siguiente respuesta está escrita por https://.com/users/3082682/cvizv en una página que ya no existe, ya que no tiene suficientes representantes para responder una pregunta, la estoy publicando. Sin créditos por mi

public String getImagePath(Uri uri){ Cursor cursor = getContentResolver().query(uri, null, null, null, null); cursor.moveToFirst(); String document_id = cursor.getString(0); document_id = document_id.substring(document_id.lastIndexOf(":")+1); cursor.close(); cursor = getContentResolver().query( android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null); cursor.moveToFirst(); String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); cursor.close(); return path; }

Editar: hay un flujo en el código; si el dispositivo tiene más de un almacenamiento externo (tarjeta sd externa, USB externo, etc.), arriba el código no funcionará en almacenes no primarios.


Nota: Esta respuesta aborda parte del problema. Para una solución completa (en forma de una biblioteca), mire la respuesta de Paul Burke .

Puede usar el URI para obtener el document id , y luego consultar MediaStore.Images.Media.EXTERNAL_CONTENT_URI o MediaStore.Images.Media.INTERNAL_CONTENT_URI (dependiendo de la situación de la tarjeta SD).

Para obtener la identificación del documento:

// Will return "image:x*" String wholeID = DocumentsContract.getDocumentId(uriThatYouCurrentlyHave); // Split at colon, use second item in the array String id = wholeID.split(":")[1]; String[] column = { MediaStore.Images.Media.DATA }; // where id is equal to String sel = MediaStore.Images.Media._ID + "=?"; Cursor cursor = getContentResolver(). query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null); String filePath = ""; int columnIndex = cursor.getColumnIndex(column[0]); if (cursor.moveToFirst()) { filePath = cursor.getString(columnIndex); } cursor.close();

Referencia: no puedo encontrar la publicación de la que se toma esta solución. Quería pedirle al póster original que contribuyera aquí. Se verá más esta noche.