Удаление изображения галереи после снятия снимка камеры

Я знаю, что это было задано разными способами, но я все еще не могу удалить изображение галереи из папки по умолчанию. Я правильно сохраняю файл на SD-карте, и я могу удалить этот файл в порядке, но файл изображения галереи по умолчанию, который отображается под папкой Camera, не будет удаляться.

Я хотел бы, чтобы изображение удалялось после возвращения активности, поскольку файл уже сохранен на SD-карте в /Coupon2.

Любые предложения?

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

Ответ 1

Мое приложение требует, чтобы я назвал намерение сделать снимок. Фотография не может быть в галерее, но вместо этого должна находиться в определенном каталоге на SD-карте.

Первоначально я просто использовал EXTRA_OUTPUT, но вскоре обнаружил следующее: - Некоторые устройства используют его полностью и пропускают галерею. - Некоторые устройства полностью игнорируют его и ТОЛЬКО используют галерею. - Некоторые устройства действительно сосут и сохраняют полноразмерное изображение в галерее и сохраняют миниатюру только в том месте, которое я хотел. (HTC вы знаете, кто вы...)

Итак, я не могу слепо удалить файл галереи, когда закончите. Последнее добавленное фото может быть или не быть тем, которое я хочу удалить. Кроме того, мне, возможно, придется скопировать этот файл, заменивший меня потом. Поскольку моя деятельность - 2000 строк, и моя компания не хотела бы, чтобы весь наш код был отправлен, я публикую только те методы, которые используются для этого. Надеюсь, это поможет.

Кроме того, я расскажу, это мое первое приложение для Android. Я не удивлюсь, если бы был лучший способ сделать это, о котором я просто не знаю, но это то, что работает для меня!

Итак, вот мое решение:

Во-первых, в моем контексте приложения я определяю переменную следующим образом:

public ArrayList<String> GalleryList = new ArrayList<String>();

Затем в моей работе я определяю метод для получения списка всех фотографий в галерее:

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

Здесь вы можете вернуть уникальное имя файла для моего нового изображения:

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

У меня есть три переменные в моей деятельности, которые хранят информацию для меня о текущем файле. Строка (путь), переменная файла и URI для этого файла:

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

Я никогда не устанавливал их напрямую, я вызываю только сеттер в пути к файлу:

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);
   }
}

Теперь я вызываю намерение сделать снимок.

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);
}

Как только это будет сделано, и активность вернется, вот мой код:

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

Ответ 2

Если кто-то ищет более простую работу по этой проблеме, вот как я решил проблему.

У меня есть кнопка захвата, и когда она нажата, намерение отправлено, то, что я добавил, это то, что я тоже иду и получаю последний идентификатор из медиа медиа и сохраняю его:

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

Затем, когда действие возвращается, я запускаю этот код для проверки последнего идентификатора изображения перед его захватом, тогда запросы для изображений после захвата имеют идентификатор больше, чем записанный, и если он больше одного, то удаляется запись, расположенная в указанном вами местоположении для сохранения камеры.

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

Для меня это было гораздо более простое решение, и я тестировал на своем HTC, у которого была эта проблема.

Еще одна заметка стороны, я изначально использовал * DATE_TAKEN * not * _ID * в качестве параметра, но, похоже, есть некоторая ошибка, что на эмуляторе некоторые из изображений, захваченных с помощью намерения, имели свои millsecond * DATE_TAKEN * раз умножается на 1000, поэтому я переключился на * _ID *, который кажется гораздо более надежным.

Ответ 3

Это приведет к удалению файла из галереи:

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);
    }
 }

Об EXTRA_OUTPUT не стандартное поведение. Я думаю, что этот псевдо-алгоритм должен работать в каждом случае:

1) Не используйте EXTRA_OUTPUT. Изображение/фото всегда будут отображаться в галерее.

2) Скопируйте файл из местоположения галереи в нужное место.

3) Удалите (с верхним кодом) файл из галереи.

Но, конечно, это кажется слишком совершенным... в некоторых устройствах (например, в оригинальной Galaxy Tab с android 2.3) вы должны использовать EXTRA_OUTPUT с ACTION_IMAGE_CAPTURE, без этого намерение не работает.

Ответ 4

Ну, вся проблема, я думаю, исходит из того факта, что вы ожидаете определенного результата от другого приложения, которое не происходит. Что (просто быть понятным) -

  • Запустите операцию, которая может делать снимок, поскольку ваше приложение не захватывает изображения.
  • Расскажите о другом приложении, в котором вы хотите сохранить picutre,
  • Используйте сохраненное изображение в указанном вами месте.
  • Но проблема в том, что другое приложение также сохранила изображение в другом месте, которое вы не хотите.

Теперь давайте посмотрим на него с другой перспективы приложения, которая захватывает изображение. Давайте рассмотрим два сценария (что возможно) -

  • Во-первых, приложение запускается с опцией имени файла или местоположения, в котором должно быть сохранено изображение.
  • Во-вторых, приложение запускается без какой-либо дополнительной информации, такой как fileName или местоположение, где изображение должно быть сохранено. (Это может произойти, если приложение захвата отображается непосредственно из меню)

Теперь в идеале, что должно было произойти, если есть дополнительная информация, например fileName или location, то он должен был использовать это местоположение, если не тогда, когда он может использовать свой собственный. Но, увы, мы из идеального мира, и поскольку ничто не написано на камне о том, что должно произойти при запуске приложения камеры, разработчик приложения для камеры будет иметь свою собственную интерпретацию.

Поскольку разные устройства имеют разные приложения для камеры, установленные по умолчанию (да, обычно используется запасная камера), полученные результаты будут/будут отличаться.

Таким образом, в некоторых камерах оно может быть сохранено только в одном месте в другом, которое может быть сохранено в папке "Камера" (так как приложение камеры всегда сохраняет сохраненное изображение в папке камеры и сохраняет его в другом месте бонус, предоставляемый приложением)

Если вы просто передадите имя файла в приложение камеры, если приложение вернется после того, как просто сделало одну фотографию? Думаю, нет. Итак, что должно быть в таком сценарии? Все это очень двусмысленно или серая область.

Теперь, если вы не хотите, чтобы он был сохранен в папке "Камера", узнайте, может ли просто получить имя файла недавно снятого изображения, а затем удалить его из вашего приложения. Или не сообщите приложению камеры, где он должен быть сохранен, просто введите имя файла и переместите его местоположение, которое вы хотите.

Если вы не получите имя файла, то вы пощадите другого разработчика приложения. (Эй, это не его вина, он просто разработал его так, как он хочет!)

Ответ 5

Я думаю, вы не можете делать то, что хотите. Это грустно, но я не могу найти другого ответа.

Если вы работаете с реализацией Google Camera, она работает нормально. Он просто не сохраняет фотографию в галерею в EXTRA_OUTPUT.

Но когда вы сталкиваетесь с некоторыми другими устройствами, они могут делать что-то совершенно другое. Это потому, что HTC, LG и, возможно, некоторые другие имеют пользовательскую реализацию камеры, и вы ничего не можете с этим поделать. Вы можете оставить его как есть или написать свою собственную камеру, которая будет работать именно так, как вам нужно.

На самом деле это не связано с этим вопросом, но однажды вы узнаете, что намерение CROP не работает на некоторых устройствах (http://groups.google.com/group/android-developers/browse_frm/thread/2dd647523926192c/4b6d087073a39607?tvc=1&pli=1). Поэтому, если вам это нужно, вам придется написать его самостоятельно.

Ответ 6

Это непростая задача для решения, но может приблизиться к сложному методу. Если для этого требуется простое и эффективное решение. Попробуйте приведенный ниже код:

  • Сохраните текущее время за миллисекунду до вызова намерения камеры.
  • OnActivityResult запрашивает изображение uri, дата принятия которого больше, чем миллисекунда на шаге 1. И удалите файл. Вот оно.
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);
        }

Ответ 7

Посмотрите здесь - это фрагмент кода, который сохраняет изображение в папку EXTRA_OUTPUT, не сохраняя его в галерее. Таким образом, в моем приложении я использовал для захвата изображения непосредственно с камеры, а затем удалял снимок.

Ответ 8

Это код, который я использую, который берет pic и сохраняет его в указанном месте

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);
}

Затем обрабатываю ответ.

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);
    }
}

Мне пришлось объявить outputFileUri как глобальную переменную, поскольку я не нашел способа получить сохраненный путь onActivityResult. Пропуская outputFileUri, вы заметите, что изображение не сохраняется в Складке камеры, но в указанном месте. Я пробовал этот код на моем Nexus1 и дешевой вещи samsung.

Надеюсь, что это поможет

Ответ 9

Я также боролся с этой проблемой. Кстати, эта проблема отмечена как Obsolete в Android трекер ошибок. По какой-то причине команда Android больше не считает это ошибкой. Возможно, потому что это связано с производителем.

Кажется, что все решения (из этой темы и других сообщений в блогах и т.д.) образуют следующий алгоритм:

  • Сохранить уникальный идентификатор последней сделанной фотографии;
  • Запустить активность камеры с помощью Intent с помощью EXTRA_OUTPUT;
  • Сделайте снимок и проверьте, изменился ли идентификатор последней сделанной фотографии в Галерее, чтобы решить, следует ли его удалять.

Что-то подобное предлагается в принятом ответе.

Но я обнаружил, что такой подход не может быть использован в производственном коде. Например, пусть образ простой ситуации:

Вы сохраняете некоторый идентификатор последней сделанной фотографии в Галерее и запускаете активность камеры. Когда пользователь делает фотографию на некоторых устройствах, активность камеры показывает диалог с кнопками Cancel и OK (или что-то в этом роде). И логика их заключается в следующем:

  • Если пользователь нажимает Cancel, он возвращается к действию камеры и может продолжать фотографировать.
  • Если он/она (пользователь) нажимает кнопку OK, действие камеры возвращает результат в ваше приложение.

Важные замечания здесь: выясняется, что на некоторых устройствах (я тестировал на LG и HTC) изображение может быть уже сохранено во время отображения этого диалогового окна.

Теперь представьте, что если пользователь по какой-то причине решает нажать кнопку Home и запускает другое приложение (например, другое приложение для камеры, в котором пользователь может делать разные фотографии!). И затем вернется в ваше приложение, где этот диалог все еще представлен, и нажимает OK. Очевидно, что в этом случае ваше приложение будет удалять неправильный файл... и разочаровать пользователя: (

Итак, после многих исследований я решил, что лучший подход к решению этой проблемы - написать свой собственный движок камеры или просто использовать некоторые сторонние библиотеки следующим образом: материальная камера.

Ответ 10

Лучше всего, вероятно, обработать класс камеры напрямую, а затем сохранить jpeg или raw, возвращенные в обратном вызове, где вы хотите.

В качестве альтернативы вы можете попытаться удалить полученное изображение с помощью _id из поставщика контента для носителя после его добавления. Просто найдите его по запросу и удалите его с помощью ContentResolver.delete, но не уверен в реализации.

Ответ 11

После битвы с этим в течение некоторого времени я убрал пулю, а написал свою собственную активность caputere камеры. Я убежден, что это намного более портативно и безопаснее, чем решения MediaStore.ACTION_IMAGE_CAPTURE. Изображение будет сохранено там, где вы его храните, и нигде больше, и вы не можете случайно удалить какой-то несвязанный файл. Кроме того, можно точно адаптировать фактическую функцию камеры к требованиям.

По причинам мобильности я использовал класс Camera, а не camera2.

Следует отметить, что все параметры камеры должны быть установлены, особенно размер изображения, режим фокусировки и режим вспышки, все они могут быть в неожиданном состоянии при запуске камеры.

Проводя это как ответ, а не как комментарий, потому что, на мой взгляд, это правильный ответ, в результате которого минимальное усилие.