Eliminar una imagen de la galería después de tomar la foto de la cámara

Sé que esto se ha preguntado de muchas maneras diferentes, pero todavía no puedo eliminar la imagen de la galería de la carpeta predeterminada. Estoy guardando el archivo en la tarjeta SD correctamente y puedo borrar bien ese archivo, pero el archivo de imagen de galería predeterminado que se muestra debajo de la carpeta Cámara no se eliminará.

Me gustaría que la imagen se elimine una vez que se devuelve la actividad, ya que el archivo ya está almacenado en la tarjeta SD en /Coupon2 .

¿Alguna sugerencia?

 public void startCamera() { Log.d("ANDRO_CAMERA", "Starting camera on the phone..."); mManufacturerText = (EditText) findViewById(R.id.manufacturer); String ManufacturerText = mManufacturerText.getText().toString(); String currentDateTimeString = new Date().toString(); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File filedir = new File(Environment.getExternalStorageDirectory()+"/Coupon2"); filedir.mkdirs(); File file = new File(Environment.getExternalStorageDirectory()+"/Coupon2", ManufacturerText+"-test.png"); outputFileUri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, CAMERA_PIC_REQUEST); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CAMERA_PIC_REQUEST && resultCode == -1) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.putExtra("crop", "true"); intent.putExtra("scale", "true"); intent.putExtra("return-data", false); intent.setDataAndType(outputFileUri, "image/*"); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, CAMERA_CROP_REQUEST); }else { SetImage(); saveState(); } } 

Mi aplicación requiere que llame a un bash para tomar una foto. La foto no puede estar en la galería, sino que debe estar en un directorio específico de la tarjeta SD.

Originalmente, acabo de utilizar EXTRA_OUTPUT, pero pronto descubrí lo siguiente: – Algunos dispositivos lo usan por completo y se saltan la galería. – Algunos dispositivos lo ignoran por completo y SÓLO usan la galería. – Algunos dispositivos realmente chupan y guardan una imagen de tamaño completo en la galería, y guardan una miniatura solo en la ubicación que yo quería. (HTC sabes quién eres …)

Por lo tanto, no puedo borrar a ciegas un archivo de la galería cuando haya terminado. La última foto agregada puede ser o no la que deseo eliminar. Además, puede que tenga que copiar ese archivo reemplazando el mío después. Como mi actividad es de 2000 líneas, y mi empresa no quiere que se publique todo nuestro código, solo publico los métodos necesarios para hacerlo. Espero que esto ayude.

Además, voy a decir, esta es mi primera aplicación de Android. No me sorprendería si hubiera una forma mejor de hacer esto que yo no sé, ¡pero esto es lo que funciona para mí!

Entonces, aquí está mi solución:

Primero, en mi contexto de aplicación, defino una variable de la siguiente manera:

 public ArrayList GalleryList = new ArrayList(); 

A continuación, en mi actividad, defino un método para obtener una lista de todas las fotos en la galería:

 private void FillPhotoList() { // initialize the list! app.GalleryList.clear(); String[] projection = { MediaStore.Images.ImageColumns.DISPLAY_NAME }; // intialize the Uri and the Cursor, and the current expected size. Cursor c = null; Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; // // Query the Uri to get the data path. Only if the Uri is valid. if (u != null) { c = managedQuery(u, projection, null, null, null); } // If we found the cursor and found a record in it (we also have the id). if ((c != null) && (c.moveToFirst())) { do { // Loop each and add to the list. app.GalleryList.add(c.getString(0)); } while (c.moveToNext()); } } 

Aquí hay un método para devolver un nombre de archivo único para mi nueva imagen:

 private String getTempFileString() { // Only one time will we grab this location. final File path = new File(Environment.getExternalStorageDirectory(), getString(getApplicationInfo().labelRes)); // // If this does not exist, we can create it here. if (!path.exists()) { path.mkdir(); } // return new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg").getPath(); } 

Tengo tres variables en mi actividad que almacenan información sobre un archivo actual. Una cadena (ruta), una variable de archivo y un URI para ese archivo:

 public static String sFilePath = ""; public static File CurrentFile = null; public static Uri CurrentUri = null; 

Nunca configuré esto directamente, solo llamo a un colocador en la ruta del archivo:

 public void setsFilePath(String value) { // We just updated this value. Set the property first. sFilePath = value; // // initialize these two CurrentFile = null; CurrentUri = null; // // If we have something real, setup the file and the Uri. if (!sFilePath.equalsIgnoreCase("")) { CurrentFile = new File(sFilePath); CurrentUri = Uri.fromFile(CurrentFile); } } 

Ahora llamo la intención de tomar una foto.

 public void startCamera() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Specify the output. This will be unique. setsFilePath(getTempFileString()); // intent.putExtra(MediaStore.EXTRA_OUTPUT, CurrentUri); // // Keep a list for afterwards FillPhotoList(); // // finally start the intent and wait for a result. startActivityForResult(intent, IMAGE_CAPTURE); } 

Una vez hecho esto, y la actividad vuelve, aquí está mi código:

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == IMAGE_CAPTURE) { // based on the result we either set the preview or show a quick toast splash. if (resultCode == RESULT_OK) { // This is ##### ridiculous. Some versions of Android save // to the MediaStore as well. Not sure why! We don't know what // name Android will give either, so we get to search for this // manually and remove it. String[] projection = { MediaStore.Images.ImageColumns.SIZE, MediaStore.Images.ImageColumns.DISPLAY_NAME, MediaStore.Images.ImageColumns.DATA, BaseColumns._ID,}; // // intialize the Uri and the Cursor, and the current expected size. Cursor c = null; Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; // if (CurrentFile != null) { // Query the Uri to get the data path. Only if the Uri is valid, // and we had a valid size to be searching for. if ((u != null) && (CurrentFile.length() > 0)) { c = managedQuery(u, projection, null, null, null); } // // If we found the cursor and found a record in it (we also have the size). if ((c != null) && (c.moveToFirst())) { do { // Check each area in the gallary we built before. boolean bFound = false; for (String sGallery : app.GalleryList) { if (sGallery.equalsIgnoreCase(c.getString(1))) { bFound = true; break; } } // // To here we looped the full gallery. if (!bFound) { // This is the NEW image. If the size is bigger, copy it. // Then delete it! File f = new File(c.getString(2)); // Ensure it's there, check size, and delete! if ((f.exists()) && (CurrentFile.length() < c.getLong(0)) && (CurrentFile.delete())) { // Finally we can stop the copy. try { CurrentFile.createNewFile(); FileChannel source = null; FileChannel destination = null; try { source = new FileInputStream(f).getChannel(); destination = new FileOutputStream(CurrentFile).getChannel(); destination.transferFrom(source, 0, source.size()); } finally { if (source != null) { source.close(); } if (destination != null) { destination.close(); } } } catch (IOException e) { // Could not copy the file over. app.CallToast(PhotosActivity.this, getString(R.string.ErrorOccured), 0); } } // ContentResolver cr = getContentResolver(); cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + c.getString(3), null); break; } } while (c.moveToNext()); } } } } } 

Si alguien está buscando un trabajo más simple para resolver este problema, así es como resolví el problema.

Tengo un botón de captura y cuando se presiona se envía la intención, lo que agregué es que también obtuve la última identificación de la imagen mediatore y la almacenaba:

 /** * Gets the last image id from the media store * @return */ private int getLastImageId(){ final String[] imageColumns = { MediaStore.Images.Media._ID }; final String imageOrderBy = MediaStore.Images.Media._ID+" DESC"; final String imageWhere = null; final String[] imageArguments = null; Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy); if(imageCursor.moveToFirst()){ int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)); imageCursor.close(); return id; }else{ return 0; } } 

Luego, cuando la actividad retorna, ejecuto este código para buscar la última identificación de imagen antes de la captura, luego las consultas de imágenes tienen una identificación más grande que la grabada y, si es más, elimina el registro ubicado en la ubicación que especifiqué para la cámara para guardar en

 /* * Checking for duplicate images * This is necessary because some camera implementation not only save where you want them to save but also in their default location. */ final String[] imageColumns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.SIZE, MediaStore.Images.Media._ID }; final String imageOrderBy = MediaStore.Images.Media._ID+" DESC"; final String imageWhere = MediaStore.Images.Media._ID+">?"; final String[] imageArguments = { Integer.toString(MyActivity.this.captureLastId) }; Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy); if(imageCursor.getCount()>1){ while(imageCursor.moveToNext()){ int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)); String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)); Long takenTimeStamp = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN)); Long size = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.SIZE)); if(path.contentEquals(MyActivity.this.capturePath)){ // Remove it ContentResolver cr = getContentResolver(); cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } ); break; } } } imageCursor.close(); 

Para mí, esta era una solución mucho más simple, y probé en mi HTC que estaba teniendo este problema.

Otra nota al margen , originalmente utilicé * DATE_TAKEN * not * _ID * como parámetro pero parece que hay algún error que en el emulador algunas de las imágenes que se capturaron a través del bash tenían su millsecond * DATE_TAKEN * veces multiplicado por 1000, así que cambió a * _ID * que parece ser mucho más robusto.

Esto eliminará el archivo de la galería:

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CAMERA_PIC_REQUEST && resultCode == RESULT_OK) { /* Copy the file to other directory or whatever you want */ // mContext is the context of the activity mContext.getContentResolver().delete(data.getData(), null, null); } } 

Acerca del comportamiento EXTRA_OUTPUT no estándar. Creo que este pseudo-algoritmo debería funcionar en todos los casos:

1) No use EXTRA_OUTPUT. La imagen / foto siempre irá a la ubicación de la galería.

2) Copie el archivo de la ubicación de la galería a la ubicación deseada.

3) Elimine (con el código superior) el archivo de la galería.

Pero, por supuesto, parece ser demasiado perfecto … en algunos dispositivos (por ejemplo, el Galaxy Tab original con Android 2.3), tienes que usar EXTRA_OUTPUT con ACTION_IMAGE_CAPTURE, sin esto el bash no funciona.

Bueno, creo que todo el problema proviene del hecho de que esperas un resultado determinado de otra aplicación que no está sucediendo. Que es (solo para ser claro) –

  • Inicie una actividad que pueda tomar una foto, ya que su aplicación no captura imágenes.
  • Indique a la otra aplicación dónde desea guardar la imagen
  • Use la imagen guardada en la ubicación que especificó.
  • Pero el problema es que la otra aplicación también ha guardado la imagen en una ubicación diferente, lo cual no es deseable.

Ahora veamos desde la perspectiva de la otra aplicación, que está capturando la imagen. Consideremos dos escenarios (lo cual es posible) –

  • Primero, la aplicación se inicia con la opción del nombre de archivo o la ubicación donde se guardará la imagen.
  • En segundo lugar, la aplicación se inicia sin ninguna información adicional como el nombre de archivo o la ubicación donde se guardará la imagen. (Esto podría suceder si la aplicación de captura se inicia directamente desde el menú)

Ahora, idealmente, lo que debería haber sucedido es que si hay información adicional como FileName o location, entonces debería haber usado esa ubicación, de lo contrario, puede usar la suya. Pero, por desgracia, somos de un mundo ideal y como nada está escrito en piedra sobre lo que debería suceder al lanzar una aplicación de cámara, el desarrollador de la aplicación de cámara tendrá su propia interpretación.

Dado que los diferentes dispositivos tienen una aplicación de cámara diferente configurada como la predeterminada (sí, la cámara de almacenamiento se suele reemplazar), los resultados obtenidos son / serán diferentes.

Por lo tanto, en algunas cámaras podría guardarse en un solo lugar y también podría guardarse en la carpeta Cámara (ya que la aplicación de la cámara siempre puede guardar la imagen capturada en la carpeta de la cámara y guardarla en una ubicación diferente es una bonificación dada por la aplicación)

Si acaba de pasar un fileName a la aplicación de la cámara, ¿debería devolver la aplicación después de tomar solo una foto? Yo creo que no. Entonces, ¿qué debería hacer en tal escenario? Es todo muy ambiguo o un área gris.

Ahora, si no desea que se guarde en la carpeta de la cámara, descubra si puede obtener el nombre de archivo de la imagen capturada recientemente y luego eliminarla de su aplicación. O no le digas a la aplicación de la cámara dónde debe guardarse, solo consigue el nombre del archivo y mueve la ubicación que quieras.

Si no obtiene el nombre del archivo, estará a merced del otro desarrollador de la aplicación. (Oye, tampoco es su culpa, ¡lo diseñó como él quiere!)

Creo que no puedes hacer lo que quieres. Eso es triste, pero no puedo encontrar otra respuesta.

Si trabajas con la implementación de Google Camera, funciona bien. Simplemente no almacena fotos en la galería en EXTRA_OUTPUT está especificado.

Pero cuando enfrentas otros dispositivos, pueden hacer algo completamente diferente. Eso es porque HTC, LG y algunos otros tienen una implementación personalizada de la cámara y no puedes hacer nada al respecto. Puede dejarlo tal cual o escribir su propia cámara que funcionará exactamente de la manera que lo necesita.

En realidad, no está relacionado con esta pregunta, pero un día descubrirá que la intención de CROP no funciona en algunos dispositivos ( http://groups.google.com/group/android-developers/browse_frm/thread/2dd647523926192c/4b6d087073a39607 ? tvc = 1 y pli = 1 ). Entonces, de nuevo, si lo necesita, tendrá que escribirlo usted mismo.

Esta no es una tarea fácil de resolver, pero puede abordar un método complicado. Si alguien necesita una solución simple y funcional para esto. Pruebe el siguiente código:

  1. Guarde la hora actual en milisegundos antes de llamar al bash de la cámara.
  2. OnActivityResult consulta la imagen uri cuya fecha de toma es mayor que el milisegundo en el paso1. Y borra el archivo. Eso es.
 String[] projection = {MediaStore.Images.ImageColumns.SIZE, MediaStore.Images.ImageColumns.DISPLAY_NAME, MediaStore.Images.ImageColumns.DATA, BaseColumns._ID,MediaStore.Images.ImageColumns.DATE_ADDED}; final String imageOrderBy = MediaStore.Images.Media._ID + " DESC"; final String selection = MediaStore.Images.Media.DATE_TAKEN+" > "+mImageTakenTime; //// intialize the Uri and the Cursor, and the current expected size. Cursor c = null; Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; c = getActivity().managedQuery(u, projection, selection, null, imageOrderBy); if(null != c && c.moveToFirst()){ ContentResolver cr = getActivity().getContentResolver(); cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + c.getString(3), null); } 

Mire aquí , es una pieza de código que guarda la imagen en la carpeta EXTRA_OUTPUT sin guardarla en la galería. De esta forma, en mi aplicación solía tomar una foto directamente de la cámara y luego borraba la foto tomada.

Este es el código que uso el cual toma una foto y la guarda en la ubicación especificada

 Uri outputFileUri; public void takePhoto() { File directory = new File(Environment.getExternalStorageDirectory() + "/HI-Tech" + "/"); if (!directory.exists()) { directory.mkdir(); } int count = 0; if (directory != null) { File[] files = directory.listFiles(); if (files != null) { count = files.length; } } count++; String imagePath = "IMAGE_" + count + ".jpg"; File file = new File(directory, imagePath); outputFileUri = Uri.fromFile(file); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, JobActivity.TAKE_PIC); } 

Luego manejo la respuesta.

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { try { if (resultCode == RESULT_OK) { if (requestCode == JobActivity.TAKE_PIC) { Bitmap bitmap = decodeFile(new File(outputFileUri.getPath()), 160, 120); } catch (Exception e) { Log.e("Error", "Unable to set thumbnail", e); } } 

Tuve que declarar el outputFileUri como una variable global, ya que no encontré la forma de adquirir la ruta guardada en ActivityResult. Al pasar el archivo outputFileUri notará que la imagen no se guarda en el seguimiento de la cámara, sino en la ubicación especificada. Probé este código en mi Nexus1 y una cosa barata de Samsung.

Espero que esto ayude

También estaba luchando con este problema. Por cierto, este problema está marcado como Obsolete en el rastreador de errores de Android. Por alguna razón, el equipo de Android ya no considera esto como un error. Tal vez porque esto está relacionado con el fabricante.

Parece que todas las soluciones (de este hilo y otras publicaciones de blog, etc.) forman el siguiente algoritmo:

  1. Guarde un identificador único de la última foto tomada;
  2. Inicie la actividad de la cámara usando Intent with EXTRA_OUTPUT ;
  3. Tome una foto y verifique si una identificación de la última foto tomada en la Galería ha cambiado para decidir si debe eliminarse.

Algo similar se propone en la respuesta aceptada.

Pero descubrí que ese enfoque no puede usarse en un código de producción. Por ejemplo, imaginemos una situación simple:

Almacena una identificación de la última foto tomada en la Galería e inicia la actividad de la cámara. Cuando el usuario toma una foto en algunos dispositivos, la actividad de la cámara muestra un cuadro de diálogo con los botones Cancel y OK (o algo así). Y la lógica detrás de ellos es la siguiente:

  • si el usuario presiona Cancel , regresa a la actividad de la cámara y puede continuar tomando fotos.
  • si él / ella (el usuario) presiona el botón OK la actividad de la cámara devuelve el resultado a su aplicación.

Las notas importantes aquí: resulta que en algunos dispositivos (probé en LG y HTC) la imagen ya se puede guardar mientras se presenta este diálogo.

Ahora imagine qué pasa si el usuario, por alguna razón, decide presionar el botón de Home e inicia otra aplicación (por ejemplo, otra aplicación de cámara donde el usuario puede tomar diferentes fotos). Y luego regresa a su aplicación donde ese cuadro de diálogo todavía se presenta y presiona OK . Obviamente, en ese caso, su aplicación eliminará el archivo incorrecto … y decepcionará al usuario 🙁

Entonces, después de investigar mucho, decidí que el mejor enfoque para superar este problema es escribir tu propio motor de cámara o simplemente usar algunas librerías de terceros como esta: cámara material .

Su mejor opción es manejar la clase Camera directamente, y luego almacenar el jpeg o raw devuelto en la callback donde lo desee.

Alternativamente, puede intentar y eliminar la imagen tomada por _id del proveedor de contenido para los medios después de que se haya agregado. Solo búsquelo por consulta y elimínelo a través de ContentResolver.delete, aunque no estoy seguro acerca de la implementación.

Después de luchar con esto por un tiempo, mordí la bala y escribí mi propia actividad de caputeré de cámara . Estoy convencido de que esto es mucho más portátil y más seguro que las soluciones MediaStore.ACTION_IMAGE_CAPTURE . La imagen se almacenará donde la almacene y en ningún otro lugar y no estará en peligro de eliminar algún archivo no relacionado por accidente. Además, es posible adaptar la función de la cámara real exactamente a los requisitos.

Por razones de portabilidad, utilicé la clase Camera , no camera2.

Vale la pena tener en cuenta que todos los parámetros de la cámara deben configurarse, especialmente el tamaño de la imagen, el modo de enfoque y el modo de flash, todos pueden estar en un estado inesperado al iniciar la cámara.

Publicar esto como una respuesta, no como un comentario, porque en mi opinión es la respuesta correcta que resulta en un esfuerzo mínimo .

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) { Bitmap photo = (Bitmap) data.getExtras().get("data"); Uri tempUri = Utils.getUri(getActivity(), photo); File finalFile = new File(getRealPathFromURI(tempUri)); finalFile.delete(); } } public String getRealPathFromURI (Uri contentUri) { String path = null; String[] proj = { MediaStore.MediaColumns.DATA }; Cursor cursor = getActivity().getContentResolver().query(contentUri, proj, null, null, null); if (cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); path = cursor.getString(column_index); } cursor.close(); return path; }