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


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

12 ответов:

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

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

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

/**
 * 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*, который кажется гораздо более надежным.

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

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 с android 2.3), вы должны использовать EXTRA_OUTPUT с ACTION_IMAGE_CAPTURE, без этого намерение не работает.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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.

Надежда это помогает

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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