Удаление изображения галереи после съемки камеры - PullRequest
64 голосов
/ 17 июня 2011

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

Я хочу, чтобы изображение было удалено послеактивность возвращается, так как файл уже хранится на 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();
    }
}

Ответы [ 12 ]

70 голосов
/ 06 июля 2011

Мое заявление требует, чтобы я позвонил с намерением сделать фотографию.Фотография не может быть в галерее, но вместо этого должна быть в определенном каталоге на 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'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());
            }
         }
      }
   }      
}
15 голосов
/ 30 января 2013

Это удалит файл из галереи:

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, без этого намерение не работает.

15 голосов
/ 19 декабря 2011

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

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

/**
 * 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 * не * _ID * в качестве параметра, но, похоже, есть какая-то ошибкачто на эмуляторе некоторые изображения, захваченные с помощью намерения, умножали на миллисекунды * DATE_TAKEN * раз на 1000, поэтому я переключился на * _ID *, который, кажется, многоруда крепкая.

5 голосов
/ 27 июня 2011

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

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

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

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

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

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

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

Если вы просто передадите fileName приложению камеры, должно ли приложение вернуться после съемки только одной фотографии?Думаю, нет.Так что же следует делать при таком сценарии?Это все очень неоднозначно или серая область.

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

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

2 голосов
/ 22 января 2015

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

  1. Сохраните текущее время в миллисекундах, прежде чем вызывать намерение камеры.
  2. 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);
        }
2 голосов
/ 27 июня 2011

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

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

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

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

1 голос
/ 08 ноября 2016

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

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

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

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

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

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

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

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

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

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

1 голос
/ 24 июня 2011

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

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 как глобальную переменную, так как я не нашел способа получить сохраненный путь наActivityResult. Передав outputFileUri, вы заметите, что изображение сохраняется не в папке «Камера», а в указанном месте. Я попробовал этот код на своем Nexus1 и дешевой самсунге.

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

1 голос
/ 23 июня 2011

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

0 голосов
/ 16 апреля 2018
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;
}
...