停止使用 Android 原生相机保存照片
Posted
技术标签:
【中文标题】停止使用 Android 原生相机保存照片【英文标题】:Stop saving photos using Android native camera 【发布时间】:2011-12-26 02:32:37 【问题描述】:我正在使用原生 android 相机并将文件保存到我的应用程序数据文件夹 (/mnt/sdcard/Android/data/com.company.app/files/Pictures/)。同时将照片的另一个副本保存到 DCIM 文件夹中。
这是我的代码:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String formattedImageName = getDateString() + ".jpg";
File image_file = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), formattedImageName);
Uri imageUri = Uri.fromFile(image_file);
intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(intent, REQUEST_FROM_CAMERA);
如何防止将额外的图像副本保存到 DCIM 文件夹?
非常感谢
【问题讨论】:
嗨 chinthaka,下面的代码 FillPhotoList() 将收集画廊中的所有图像,而不是其他方法,movingCapturedImageFromDCIMtoMerchandising() 将通过 arralist 并找到最后捕获的图像并将其从 DCIM 中删除。跨度> 【参考方案1】:您可以使用以下内容: 首先,我们通过检查哪个是最后修改的图像来获取最后保存的图像。然后检查最后修改时间是否在最后几秒钟内。您可能还需要检查相机存储图像的确切位置。
private boolean deleteLastFromDCIM()
boolean success = false;
try
File[] images = new File(Environment.getExternalStorageDirectory()
+ File.separator + "DCIM/Camera").listFiles();
File latestSavedImage = images[0];
for (int i = 1; i < images.length; ++i)
if (images[i].lastModified() > latestSavedImage.lastModified())
latestSavedImage = images[i];
// OR JUST Use success = latestSavedImage.delete();
success = new File(Environment.getExternalStorageDirectory()
+ File.separator + "DCIM/Camera/"
+ latestSavedImage.getAbsoluteFile()).delete();
return success;
catch (Exception e)
e.printStackTrace();
return success;
【讨论】:
我在想,如果您的应用碰巧在手机上,而手机上没有将照片保存到该目录“DCIM/Camera/”,您会不会冒删除一些可怜用户的家庭相册的风险? @ Sixtoo 评论的解决方案是检查时间 - 如果文件在几秒钟前有最后修改 - 然后删除它【参考方案2】:不幸的是,一些智能手机将图像保存在另一个文件夹中,例如 DCIM/100MEDIA。所以不能依赖这些解决方案。我更喜欢这样使用:
String[] projection = new String[]
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.MIME_TYPE;
final Cursor cursor = managedQuery(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,projection, null, null,
MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if(cursor != null)
cursor.moveToFirst();
// you will find the last taken picture here and can delete that
我试图找出是否存在第二个副本并删除该副本。我使用上面的代码找到了最后一张照片。
注意:使用managedQuery后不要使用cursor.close();
,光标留给Android系统管理,不要调用。可以看managedQuery()
注意2:managedQuery 方法已被弃用,应避免使用,改为实现 CursorLoaders。
【讨论】:
小心:这是非常非常危险的。在某些设备中,我们从应用中拍摄的图片不会复制到图库。在这种情况下,如果我们删除最后一张拍摄的照片,它会返回从相机应用程序拍摄的照片,所以我们最终会删除错误的照片,而不是从我们的应用程序拍摄的照片。因此,最重要的是,仅删除创建第二个副本的设备(例如 HTC One M8)从图库中拍摄的最后一张照片。 @whoami :我们如何知道第二个副本已创建?我在 Moto G4 Plus 上遇到了这个问题。 没办法,如果你使用相机意图..如果你不想创建第二个副本,你必须在你的应用程序中实现相机 API。【参考方案3】:检查此代码..
private void FillPhotoList()
// initialize the list!
GalleryList.clear();
String[] projection = MediaStore.Images.ImageColumns.DISPLAY_NAME ;
for(int i=0;i<projection.length;i++)
Log.i("InfoLog","projection "+projection[0].toString());
// intialize the Uri and the Cursor, and the current expected size.
Cursor c = null;
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Log.i("InfoLog","FillPhoto Uri u "+u.toString());
// 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.
GalleryList.add(c.getString(0)); // adding all the images sotred in the mobile phone(Internal and SD card)
while (c.moveToNext());
Log.i(INFOLOG,"gallery size "+ GalleryList.size());
这就是方法发挥所有魔力的地方
/** Method will check all the photo is the gallery and delete last captured and move it to the required folder.
*/
public void movingCapturedImageFromDCIMtoMerchandising()
// 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.
for(int i=0;i<projection.length;i++)
Log.i("InfoLog","on activityresult projection "+projection[i]);
//+" "+projection[1]+" "+projection[2]+" "+projection[3] this will be needed if u remove the for loop
Cursor c = null;
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Log.i("InfoLog","on activityresult Uri u "+u.toString());
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))
//****u is the place from data will come and projection is the specified data what we want
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 gallery we built before.
boolean bFound = false;
for (String sGallery : GalleryList)
if (sGallery.equalsIgnoreCase(c.getString(1)))
bFound = true;
Log.i("InfoLog","c.getString(1) "+c.getString(1));
break;
// To here we looped the full gallery.
if (!bFound) //the file which is newly created and it has to be deleted from the gallery
// 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.
ToastMaker.makeToast(this, "Error Occured", 0);
//****deleting the file which is in the gallery
Log.i(INFOLOG,"imagePreORNext1 "+imagePreORNext);
Handler handler = new Handler();
//handler.postDelayed(runnable,300);
Log.i(INFOLOG,"imagePreORNext2 "+imagePreORNext);
ContentResolver cr = getContentResolver();
cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + c.getString(3), null);
break;
while (c.moveToNext());
【讨论】:
感谢您的回复。您认为我们可以在与 Picasa 同步之前删除 mediaStore 吗?你知道有什么方法可以停止将文件保存到 mediaStroe 吗? 你能告诉我这个“CurrentFile”是什么吗?我必须在哪里定义这个? 它是您提供给捕获图像的文件的名称 阿莫尔,这行得通吗?因为在保存重复的照片时,它会获得自己的文件名。我们无法改变这一点。 谢谢阿莫尔。终于可以删除媒体文件了。【参考方案4】:Parth 的一个不错的解决方案。但这对于将图像保存在 DCIM/Camera 中的三星来说是件好事。一些手机 - 索尼爱立信、HTC 将它们保存在 DCIM/100MEDIA、DCIM/100ANDRO 等文件夹中,所以我稍微修改了代码:
private boolean deleteLastFromDCIM()
boolean success = false;
try
//Samsungs:
File folder = new File(Environment.getExternalStorageDirectory() + File.separator + "DCIM/Camera");
if(!folder.exists()) //other phones:
File[] subfolders = new File(Environment.getExternalStorageDirectory() + File.separator + "DCIM").listFiles();
for(File subfolder : subfolders)
if(subfolder.getAbsolutePath().contains("100"))
folder = subfolder;
break;
if(!folder.exists())
return false;
File[] images = folder.listFiles();
File latestSavedImage = images[0];
for (int i = 1; i < images.length; ++i)
if (images[i].lastModified() > latestSavedImage.lastModified())
latestSavedImage = images[i];
success = latestSavedImage.delete();
return success;
catch (Exception e)
e.printStackTrace();
return success;
【讨论】:
这对我没有任何帮助。我的应用程序没有崩溃,但照片仍然存在。你能说明一下它的用法吗? 这确实为我删除了图像,但在图库应用程序中,我仍然会在图像所在的位置看到损坏的缩略图。 你们知道,这是一种解决方案,适用于特定手机上特定应用程序的特定情况。在不断变化的(我应该说是狂野的?)Android 世界中,没有什么是不变的而不是持久的。此外,并非每个发帖人都有时间为每个设备更新他的答案...【参考方案5】:我在使用 Moto Z Force (7.1.1) 时遇到了类似的问题。我在意图上定义了MediaStore.EXTRA_OUTPUT
,但仍然在相机目录中创建了一个重复文件。
我需要在其他设备上进行测试,但这是我针对此问题采取的一种方法。我没有尝试查找特定的相机目录,而是使用MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME
位置。
这是我的代码 sn-p:
private void removeCameraDuplicate()
String[] proj =
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns._ID ;
String selection = MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME + " = ? ";
String[] selectionArgs = new String[] "Camera" ;
Cursor cursor = mActivity.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, proj, selection, selectionArgs, MediaStore.Images.ImageColumns.DATE_TAKEN + " desc");
if (cursor != null)
int idxPath = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
if (cursor.getCount() > 0 && idxPath > -1 && cursor.moveToFirst())
File original = new File(mMediaPath);
File cameraDupe = new File(cursor.getString(idxPath));
if (original.exists() && cameraDupe.exists())
LogUtils.LOGE("***> camera", "original " + original.length());
LogUtils.LOGE("***> camera", "original " + original.lastModified());
LogUtils.LOGE("***> camera", "duplicate " + cameraDupe.length());
LogUtils.LOGE("***> camera", "duplicate " + cameraDupe.lastModified());
if (original.length() == cameraDupe.length() && original.lastModified() == cameraDupe.lastModified())
if (cameraDupe.delete())
LogUtils.LOGE("***> camera", "duplicate deleted");
cursor.close();
【讨论】:
以上是关于停止使用 Android 原生相机保存照片的主要内容,如果未能解决你的问题,请参考以下文章
Android:BroadcastReceiver 意图检测拍摄的相机照片?