studio picture intent getdata from fileuriexposedexception example data action_image_capture android android-intent camera return-value android-camera-intent

picture - onactivityresult camera android



Android ACTION_IMAGE_CAPTURE intenciĆ³n (14)

Estamos tratando de usar la aplicación de cámara nativa para que el usuario tome una nueva imagen. Funciona muy bien si EXTRA_OUTPUT extra y devuelve la pequeña imagen de mapa de bits. Sin embargo, si ponemos putExtra(EXTRA_OUTPUT,...) en el intento antes de iniciarlo, todo funciona hasta que intente presionar el botón "Aceptar" en la aplicación de la cámara. El botón "Ok" simplemente no hace nada. La aplicación de la cámara permanece abierta y nada se bloquea. Podemos cancelarlo, pero el archivo nunca se escribe. ¿Qué es exactamente lo que tenemos que hacer para obtener ACTION_IMAGE_CAPTURE y escribir la imagen tomada en un archivo?

Editar: Esto se hace a través del intento MediaStore.ACTION_IMAGE_CAPTURE , solo para ser claro


Creé una biblioteca simple que administrará la elección de imágenes de diferentes fuentes (Galería, Cámara), tal vez la guarde en alguna ubicación (tarjeta SD o memoria interna) y devuelva la imagen, así que por favor Android-ImageChooser para usarla y mejorarla - Android-ImageChooser .


El archivo debe ser editable por la cámara, como señaló Praveen .

En mi uso, quería almacenar el archivo en el almacenamiento interno. Hice esto con:

Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (i.resolveActivity(getPackageManager()!=null)){ try{ cacheFile = createTempFile("img",".jpg",getCacheDir()); cacheFile.setWritavle(true,false); }catch(IOException e){} if(cacheFile != null){ i.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(cacheFile)); startActivityForResult(i,REQUEST_IMAGE_CAPTURE); } }

Aquí cacheFile es un archivo global utilizado para referirse al archivo que se escribe. Luego, en el método de resultado, el intento devuelto es nulo. Entonces el método para procesar la intención se ve así:

protected void onActivityResult(int requestCode,int resultCode,Intent data){ if(requestCode != RESULT_OK){ return; } if(requestCode == REQUEST_IMAGE_CAPTURE){ try{ File output = getImageFile(); if(output != null && cacheFile != null){ copyFile(cacheFile,output); //Process image file stored at output cacheFile.delete(); cacheFile=null; } }catch(IOException e){} } }

Aquí getImageFile() es un método de utilidad para nombrar y crear el archivo en el que se debe almacenar la imagen, y copyFile() es un método para copiar un archivo.


El flujo de trabajo que describes debe funcionar como lo has descrito. Podría ser útil si pudieras mostrarnos el código alrededor de la creación del Intento. En general, el siguiente patrón debería permitirle hacer lo que está intentando.

private void saveFullImage() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File(Environment.getExternalStorageDirectory(), "test.jpg"); outputFileUri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, TAKE_PICTURE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) { // Check if the result includes a thumbnail Bitmap if (data == null) { // TODO Do something with the full image stored // in outputFileUri. Perhaps copying it to the app folder } } }

Tenga en cuenta que es la actividad de la cámara la que creará y guardará el archivo, y en realidad no es parte de su aplicación, por lo que no tendrá permiso de escritura en la carpeta de la aplicación. Para guardar un archivo en la carpeta de la aplicación, cree un archivo temporal en la tarjeta SD y muévalo a la carpeta de la aplicación en el controlador onActivityResult .


Es muy simple resolver este problema con Activity Result Code Simple try this method

if (reqCode == RECORD_VIDEO) { if(resCode == RESULT_OK) { if (uri != null) { compress(); } } else if(resCode == RESULT_CANCELED && data!=null){ Toast.makeText(MainActivity.this,"No Video Recorded",Toast.LENGTH_SHORT).show(); } }


He pasado por varias estrategias de captura de fotos, y siempre parece haber un caso, una plataforma o ciertos dispositivos, donde algunas o todas las estrategias anteriores fallarán de maneras inesperadas. Pude encontrar una estrategia que utiliza el código de generación de URI a continuación, que parece funcionar en la mayoría de los casos, si no en todos.

mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues()); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri); startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);

Para contribuir aún más a la discusión y ayudar a los recién llegados, he creado una aplicación de prueba / muestra que muestra varias estrategias diferentes para la implementación de captura de fotos. Las contribuciones de otras implementaciones son definitivamente alentadas para agregar a la discusión.

https://github.com/deepwinter/AndroidCameraTester


Para seguir con el comentario anterior de Yenchi, el botón OK tampoco hará nada si la aplicación de la cámara no puede escribir en el directorio en cuestión.

Eso significa que no puede crear el archivo en un lugar que solo puede escribir en su aplicación (por ejemplo, algo en getCacheDir()) Algo bajo getExternalFilesDir() debería funcionar, sin embargo.

Sería bueno si la aplicación de la cámara imprimiera un mensaje de error en los registros si no pudiera escribir en la ruta especificada EXTRA_OUTPUT , pero no encontré ninguno.


Puedes usar este código

private Intent getCameraIntent() { PackageManager packageManager = mContext.getPackageManager(); List<ApplicationInfo> list = packageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES); Intent main = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); List<ResolveInfo> launchables = packageManager.queryIntentActivities(main, 0); if (launchables.size() == 1) return packageManager.getLaunchIntentForPackage(launchables.get(0).activityInfo.packageName); else for (int n = 0; n < list.size(); n++) { if ((list.get(n).flags & ApplicationInfo.FLAG_SYSTEM) == 1) { Log.d("TAG", "Installed Applications : " + list.get(n).loadLabel(packageManager).toString()); Log.d("TAG", "package name : " + list.get(n).packageName); String defaultCameraPackage = list.get(n).packageName; if (launchables.size() > 1) for (int i = 0; i < launchables.size(); i++) { if (defaultCameraPackage.equals(launchables.get(i).activityInfo.packageName)) { return packageManager.getLaunchIntentForPackage(defaultCameraPackage); } } } } return null; }


Sé que esto ha sido respondido antes, pero sé que muchas personas se tropiezan con esto, así que voy a agregar un comentario.

Tuve este mismo problema en mi Nexus One. Esto era del archivo que no existía en el disco antes de que comenzara la aplicación de la cámara. Por lo tanto, me aseguré de que el archivo existente antes comenzara la aplicación de la cámara. Aquí hay un código de muestra que utilicé:

String storageState = Environment.getExternalStorageState(); if(storageState.equals(Environment.MEDIA_MOUNTED)) { String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg"; _photoFile = new File(path); try { if(_photoFile.exists() == false) { _photoFile.getParentFile().mkdirs(); _photoFile.createNewFile(); } } catch (IOException e) { Log.e(TAG, "Could not create file.", e); } Log.i(TAG, path); _fileUri = Uri.fromFile(_photoFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE ); intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri); startActivityForResult(intent, TAKE_PICTURE); } else { new AlertDialog.Builder(MainActivity.this) .setMessage("External Storeage (SD Card) is required./n/nCurrent state: " + storageState) .setCancelable(true).create().show(); }

Primero creo un nombre de archivo único (algo) usando un hash MD5 y lo coloco en la carpeta apropiada. Luego verifico si existe (no debería, pero es una buena práctica consultarlo de todos modos). Si no existe, obtengo el directorio padre (una carpeta) y creo la jerarquía de la carpeta (por lo tanto, si las carpetas que conducen a la ubicación del archivo no existen, lo harán después de esta línea. Luego, después de eso Creo el archivo. Una vez que se crea el archivo, obtengo el Uri y lo paso al intento y luego el botón OK funciona como se esperaba y todo está dorado.

Ahora, cuando se presiona el botón Aceptar en la aplicación de la cámara, el archivo estará presente en la ubicación especificada. En este ejemplo, sería /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg

No es necesario copiar el archivo en "onActivityResult" como se publicó anteriormente.


Te recomiendo que sigas la publicación de capacitación de Android para capturar una foto. Muestran en un ejemplo cómo tomar fotos pequeñas y grandes. También puedes descargar el código fuente desde here


Tuve el mismo problema cuando el botón Aceptar en la aplicación de la cámara no hizo nada, tanto en el emulador como en el nexo uno.

El problema desapareció después de especificar un nombre de archivo seguro sin espacios en blanco, sin caracteres especiales, en MediaStore.EXTRA_OUTPUT Además, si especifica un archivo que reside en un directorio que aún no se ha creado, primero debe crearlo. La aplicación de la cámara no hace mkdir por ti.


Tuve el mismo problema y lo solucioné con lo siguiente:

El problema es que cuando especificas un archivo al que solo tu aplicación tiene acceso (por ejemplo, llamando a getFileStreamPath("file"); )

Es por eso que me aseguré de que el archivo dado realmente existe y de que TODOS tienen acceso de escritura.

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); File outFile = getFileStreamPath(Config.IMAGE_FILENAME); outFile.createNewFile(); outFile.setWritable(true, false); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,Uri.fromFile(outFile)); startActivityForResult(intent, 2);

De esta manera, la aplicación de la cámara tiene acceso de escritura al Uri dado y el botón OK funciona bien :)


este es un error bien documentado en algunas versiones de Android. es decir, en las compilaciones de experiencia de google de Android, la captura de imágenes no funciona como está documentado. Lo que generalmente he usado es algo como esto en una clase de utilidades.

public boolean hasImageCaptureBug() { // list of known devices that have the bug ArrayList<String> devices = new ArrayList<String>(); devices.add("android-devphone1/dream_devphone/dream"); devices.add("generic/sdk/generic"); devices.add("vodafone/vfpioneer/sapphire"); devices.add("tmobile/kila/dream"); devices.add("verizon/voles/sholes"); devices.add("google_ion/google_ion/sapphire"); return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/" + android.os.Build.DEVICE); }

luego, cuando lanzo la captura de imágenes, creo un intento que busca el error.

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); if (hasImageCaptureBug()) { i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp"))); } else { i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); } startActivityForResult(i, mRequestCode);

luego en la actividad a la que vuelvo, hago diferentes cosas en función del dispositivo.

protected void onActivityResult(int requestCode, int resultCode, Intent intent) { switch (requestCode) { case GlobalConstants.IMAGE_CAPTURE: Uri u; if (hasImageCaptureBug()) { File fi = new File("/sdcard/tmp"); try { u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null)); if (!fi.delete()) { Log.i("logMarker", "Failed to delete " + fi); } } catch (FileNotFoundException e) { e.printStackTrace(); } } else { u = intent.getData(); } }

esto le ahorra tener que escribir una nueva aplicación de cámara, pero este código tampoco es bueno. los grandes problemas son

  1. nunca obtienes imágenes de tamaño completo de los dispositivos con el error. obtiene imágenes de 512 px de ancho que se insertan en el proveedor de contenido de imagen. en dispositivos sin el error, todo funciona como documento, obtienes una gran imagen normal.

  2. tienes que mantener la lista. tal como está escrito, es posible que los dispositivos se flasheen con una versión de Android (digamos compilaciones de cyanogenmod ) que tiene el error corregido. si eso sucede, su código se bloqueará. la solución es usar la huella digital completa del dispositivo.


para que la cámara escriba en sdcard pero guarde un nuevo álbum en la aplicación de la galería. Uso esto:

File imageDirectory = new File("/sdcard/signifio"); String path = imageDirectory.toString().toLowerCase(); String name = imageDirectory.getName().toLowerCase(); ContentValues values = new ContentValues(); values.put(Media.TITLE, "Image"); values.put(Images.Media.BUCKET_ID, path.hashCode()); values.put(Images.Media.BUCKET_DISPLAY_NAME,name); values.put(Images.Media.MIME_TYPE, "image/jpeg"); values.put(Media.DESCRIPTION, "Image capture by camera"); values.put("_data", "/sdcard/signifio/1111.jpg"); uri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values); Intent i = new Intent("android.media.action.IMAGE_CAPTURE"); i.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(i, 0);

Tenga en cuenta que deberá generar un nombre de archivo único cada vez y reemplazar el 1111.jpg que escribí. Esto fue probado con Nexus One. el uri se declara en la clase privada, por lo que en el resultado de la actividad puedo cargar la imagen desde el uri a imageView para obtener una vista previa si es necesario.


protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_CANCELED) { //do not process data, I use return; to resume activity calling camera intent enter code here } }