照相机意图照片拍摄后删除图库图像
我知道这已被问了许多不同的方式,但我似乎仍然不能从默认文件夹中删除图库图像。 我正确地将文件保存到SD卡上,我可以删除该文件,但文件夹Camera下显示的默认图库文件不会被删除。
由于文件已存储在/Coupon2
下的SD卡上,所以一旦活动返回,我希望图像被删除。
有什么build议么?
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(); } }
我的申请要求我打电话给一个照片的意图。 该照片不能在画廊中,而是必须在SD卡上的特定目录中。
最初我只是使用EXTRA_OUTPUT,但我很快发现了以下内容: – 一些设备完全使用它,并跳过画廊。 – 有些设备完全忽略它,只使用画廊。 – 一些设备真的吸吮,并保存一个全尺寸的图像到画廊,并保存一个缩略图只到我想要的位置。 (HTC,你知道你是谁…)
所以,当我完成后,我不能盲目删除一个图库文件。 最后添加的照片可能是也可能不是我想要删除的照片。 此外,我可能需要复制该文件,replace我自己的。 因为我的活动是2000行,而且我的公司不希望我们所有的代码都被发布,所以我只发布了这样做的方法。 希望这有助于。
另外,我会说,这是我的第一个Android应用程序。 如果有一个更好的方法来做到这一点,我就不会感到惊讶,但是这是我的工作。
所以,这是我的解决scheme:
首先,在我的应用程序环境中,我定义了一个variables如下:
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(); }
我在我的Activity中有三个variables,用于存储当前文件的信息。 一个string(path),一个文件variables,以及该文件的URI:
public static String sFilePath = ""; public static File CurrentFile = null; public static Uri CurrentUri = null;
我从来没有直接设置这些,我只是在文件path上调用setter:
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()); } } } } }
如果有人正在寻找一个更简单的解决这个问题,这是我如何解决这个问题。
我有一个捕获button,当它被按下时,意图被发送,我添加的是,我也去,从图像mediastore获取最后一个ID并将其存储:
/** * 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; } }
然后,当活动返回时,我运行此代码来检查捕获前的最后一个图像ID,然后捕获后的图像查询有一个大于录制的ID, 如果它是多于一个删除位于我指定的相机位置的logging保存。
/* * 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();
对我来说,这是一个更简单的解决scheme,我testing了我的macros达电这个问题。
另一方面说明 ,我最初使用* 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不是标准行为。 我认为这个伪algorithm应该适用于任何情况:
1)不要使用EXTRA_OUTPUT。 图片/照片总是会去画廊的位置。
2)从图库位置复制文件到所需的位置。
3)从库中删除(用上面的代码)文件。
但是,当然,它似乎是太完美了…在某些设备(例如与Android 2.3的原始Galaxy Tab),你必须使用ACTION_IMAGE_CAPTURE EXTRA_OUTPUT,没有这个意图不起作用。
那么我认为所有的问题都来自于你正在期待另一个应用程序不会发生某种结果。 这是(只是要清楚) –
- 启动一个可以拍照的活动,因为你的应用程序不捕获图像。
- 告诉另一个应用程序你要保存picutre的地方
- 在指定的位置使用保存的图像。
- 但问题是其他应用程序也保存在不同的位置的图像,你不希望它。
现在让我们从其他应用程序的angular度来看待它,这是捕获图像。 让我们考虑两种情况(这是可能的) –
- 首先,启动应用程序,并select要保存图像的文件名或位置。
- 其次,应用程序的启动没有任何额外的信息,如文件的名称或图像将被保存的位置(这可能发生,如果捕获应用程序直接从菜单中启动)
现在理想情况是,如果有文件名或位置等额外的信息,那么他应该使用那个位置,如果不是,那么他可以使用自己的位置。 但是,唉,我们是来自一个理想的世界,因为当你启动一个相机应用程序会发生什么事情,相机应用程序开发人员将有他自己的解释。
由于不同的设备有不同的相机应用程序设置为默认(是的,股票相机通常被取代)所得到的结果是/将是不同的。
因此,在某些相机中,可能只保存在其他相机中的一个地方,也可能保存在相机文件夹中(因为相机应用程序可能总是将拍摄的图像保存在相机文件夹中,并将其保存在相机文件夹中,应用程序)
如果你只是传递一个文件名到相机应用程序应该返回后,只需拍摄一张照片? 我想不是。 那么在这种情况下应该怎样? 这一切都很模糊或灰色地带。
现在,如果您不希望将其保存在“相机”文件夹中,请查看是否可以获取最近捕获的图像的文件名,然后将其从应用程序中删除 。 或者不要告诉相机应用程序需要保存的地方,只需要获取文件名并将其移动到您想要的位置即可。
如果你没有得到文件名,那么你是在其他应用程序开发人员的摆布。 (嘿!这也不是他的错,他只是按照自己的意思devise的!)
我想你不能做你想做的事。 这是可悲的,但我找不到另一个答案。
如果你使用谷歌相机实施工作正常。 它只是不指定在EXTRA_OUTPUT库中存储照片。
但是当你面对其他一些设备时,他们可能会做一些完全不同的事 这是因为macros达电,LG和其他一些其他的有自定义的摄像头执行,你不能做任何事情。 您可以保持原样,或者编写自己的相机,以完全符合您的需要的方式工作。
其实这跟这个问题没有关系,但有一天你会发现CROP意图在某些设备上不起作用( http://groups.google.com/group/android-developers/browse_frm/thread/2dd647523926192c/4b6d087073a39607 ?tvc = 1&pli = 1 )。 所以如果你需要它,你必须自己写。
这不是一个容易解决的任务,但可以采取一个棘手的方法。如果任何人需要一个简单的工作解决scheme。 试试下面的代码:
- 在调用相机意图之前,以毫秒为单位保存当前时间。
- OnActivityResult查询在step1中采用date大于毫秒的图像uri。 并删除该文件。 而已。
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作为一个全局variables,因为我发现没有办法获得保存pathonActivityResult。 通过传递outputFileUri,你会注意到图像没有保存在Camera folde中,而是保存在指定的位置。 我已经在我的Nexus1上试过这个代码了,而且是一个便宜的三星的东西。
希望这可以帮助
我也在为这个问题苦苦挣扎。 顺便说一句,这个问题在Android bug跟踪器中被标记为Obsolete
。 出于某种原因,Android团队不会将此视为错误。 也许是因为这是制造商相关的。
看来,所有的解决scheme(从这个线程和其他博客文章等)形成以下algorithm:
- 保存上次拍摄照片的唯一标识符;
- 使用
Intent
和EXTRA_OUTPUT
启动相机活动; - 拍照并检查图库中上次拍摄的照片的ID是否已更改,以决定是否应删除。
在接受的答案中提出了类似的东西。
但是我发现这种方法不能用在生产代码中。 例如,让我们来形象一个简单的情况:
您在图库中存储了最近拍摄的照片的一些标识并启动相机活动。 当用户在某些设备上拍摄照片时,相机活动会显示一个对话框,其中包含“ Cancel
和“ OK
button(或类似的内容)。 其背后的逻辑如下:
- 如果用户按下
Cancel
他将返回到相机活动,并可以继续拍照。 - 如果他/她(用户)按
OK
button,相机活动将结果返回给您的应用程序。
这里的重要注意事项:事实certificate,在某些设备上(我在LG和HTC上testing过),在显示此对话框时,图像可以保存 。
现在想象一下,如果用户出于某种原因决定点击Home
button并启动另一个应用程序(例如用户可以拍摄不同照片的另一个相机应用程序!)。 然后返回到您的应用程序,该对话框仍然呈现,并按下OK
。 很明显,在这种情况下,你的应用程序将删除错误的文件…并让用户失望:(
所以经过大量的研究之后,我决定克服这个问题的最好方法是编写自己的相机引擎,或者使用像这样的第三方库: 素材相机 。
最好的办法是直接处理Camera类,然后将jpeg或raw返回到你想要的callback中。
或者,您可以在添加媒体后,尝试从媒体的内容提供商中删除由_id拍摄的图像。 只要通过查询find它,并通过ContentResolver.delete删除它,但不知道实施。
经过一段时间的努力,我咬紧牙关, 写下自己的摄像头活动 。 我确信这比MediaStore.ACTION_IMAGE_CAPTURE
解决scheme更便携和更安全。 图像将被存储在你存储的地方,无处不在,你没有危险删除一些无关的文件意外。 另外,可以根据实际需要调整实际的摄像机function。
出于便携性原因,我使用了Camera
类,而不是camera2。
值得注意的是,相机的参数都应该被设置,尤其是图片尺寸,对焦模式和闪光模式,它们在启动相机时都可能处于意想不到的状态。
发表这个答案,而不是作为一个评论,因为在我看来这是一个正确的答案导致最小的努力 。