Android:删除一张图片

35

我正在从我的应用程序中删除一张图片文件。我曾经使用以下代码完成这个任务:

new  File(filename).delete ();

这实际上删除了文件,但图库中仍可见该图像。

经过搜索后,我发现我们应该使用getContentResolver().delete(Uri.fromFile(file), null, null);来删除。

但是,这里出现了异常:

未知的文件URL。java.lang.IllegalArgumentException: Unknown URL file:///mnt/sdcard/DCIM/Camera/IMG_20120523_122612.jpg

当我用任何文件浏览器查看时,发现该特定图像存在。请帮我解决这个问题。在物理删除图像时是否有其他更新图库的方法?


重置你的 ADB 然后检查。 - Mohammed Azharuddin Shaikh
11个回答

37

使用下面的代码,它可能会对你有所帮助。

File fdelete = new File(file_dj_path);
if (fdelete.exists()) {
    if (fdelete.delete()) {
        System.out.println("file Deleted :" + file_dj_path);
    } else {
        System.out.println("file not Deleted :" + file_dj_path);
    }
}

在删除图片后刷新相册,请使用以下代码发送广播

(适用于 < KITKAT API 14)

 sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
 Uri.parse("file://" +  Environment.getExternalStorageDirectory())));

对于 >= KITKAT API 14,请使用以下代码

MediaScannerConnection.scanFile(this, new String[] { Environment.getExternalStorageDirectory().toString() }, null, new MediaScannerConnection.OnScanCompletedListener() {
            /*
             *   (non-Javadoc)
             * @see android.media.MediaScannerConnection.OnScanCompletedListener#onScanCompleted(java.lang.String, android.net.Uri)
             */
            public void onScanCompleted(String path, Uri uri) 
              {
                  Log.i("ExternalStorage", "Scanned " + path + ":");
                  Log.i("ExternalStorage", "-> uri=" + uri);
              }
            });

原因是:

ACTION_MEDIA_MOUNTED

在KITKAT(API 14)中已被弃用。


编辑于 04-09-2015

它的工作正常,请检查下面的代码。

public void deleteImage() {
        String file_dj_path = Environment.getExternalStorageDirectory() + "/ECP_Screenshots/abc.jpg";
        File fdelete = new File(file_dj_path);
        if (fdelete.exists()) {
            if (fdelete.delete()) {
                Log.e("-->", "file Deleted :" + file_dj_path);
                callBroadCast();
            } else {
                Log.e("-->", "file not Deleted :" + file_dj_path);
            }
        }
    }

    public void callBroadCast() {
        if (Build.VERSION.SDK_INT >= 14) {
            Log.e("-->", " >= 14");
            MediaScannerConnection.scanFile(this, new String[]{Environment.getExternalStorageDirectory().toString()}, null, new MediaScannerConnection.OnScanCompletedListener() {
                /*
                 *   (non-Javadoc)
                 * @see android.media.MediaScannerConnection.OnScanCompletedListener#onScanCompleted(java.lang.String, android.net.Uri)
                 */
                public void onScanCompleted(String path, Uri uri) {
                    Log.e("ExternalStorage", "Scanned " + path + ":");
                    Log.e("ExternalStorage", "-> uri=" + uri);
                }
            });
        } else {
            Log.e("-->", " < 14");
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
                    Uri.parse("file://" + Environment.getExternalStorageDirectory())));
        }
    }

以下是日志记录

09-04 14:27:11.085    8290-8290/com.example.sampleforwear E/-->﹕ file Deleted :/storage/emulated/0/ECP_Screenshots/abc.jpg
09-04 14:27:11.085    8290-8290/com.example.sampleforwear E/-->﹕ >= 14
09-04 14:27:11.152    8290-8290/com.example.sampleforwear E/﹕ appName=com.example.sampleforwear, acAppName=/system/bin/surfaceflinger
09-04 14:27:11.152    8290-8290/com.example.sampleforwear E/﹕ 0
09-04 14:27:15.249    8290-8302/com.example.sampleforwear E/ExternalStorage﹕ Scanned /storage/emulated/0:
09-04 14:27:15.249    8290-8302/com.example.sampleforwear E/ExternalStorage﹕ -> uri=content://media/external/file/2416

2
它适用于文件,无论文件的扩展名是什么。 - Trikaldarshiii
8
这个解决方案不起作用(或者不再起作用)。使用这两种方法仍然会在相册中保留图片。 - Bisclavret
@Bisclavret:这个解决方案很好,检查一下我的编辑答案,你也可以尝试使用那段代码(在最新设备上也适用)。 - Dhaval Parmar
1
由于某些原因,这对我不起作用。日志显示图像已被删除,但我仍然可以在相册中找到它。 - jlively
1
“EDITED 04-09-2015”版本适用于单个文件(4.4&6.0),但不适用于目录路径。如果您想要删除目录,则需要将文件路径列表发送到MediaScannerConnection。 - LEO
显示剩余5条评论

35
我看到很多答案建议使用
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" +  Environment.getExternalStorageDirectory())));

这个方法能够正常工作,但会导致媒体扫描器重新扫描设备上的媒体文件。更高效的方法是通过Media Store内容提供者进行查询/删除操作:


// Set up the projection (we only need the ID)
String[] projection = { MediaStore.Images.Media._ID };

// Match on the file path
String selection = MediaStore.Images.Media.DATA + " = ?";
String[] selectionArgs = new String[] { file.getAbsolutePath() };

// Query for the ID of the media matching the file path
Uri queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver contentResolver = getContentResolver();
Cursor c = contentResolver.query(queryUri, projection, selection, selectionArgs, null);
if (c.moveToFirst()) {
    // We found the ID. Deleting the item via the content provider will also remove the file
    long id = c.getLong(c.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
    Uri deleteUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
    contentResolver.delete(deleteUri, null, null);
} else {
    // File not found in media store DB
}
c.close();

1
重命名前请先删除...媒体扫描器会自动/最终识别您的新文件(已更名)。 - Tanner Perrien
仍然不太好,想象一下删除一个文件夹。然后循环遍历所有已删除的路径,并从内容解析器中删除它们。听起来是一个非常缓慢的过程。 - xmen
1
这是唯一在所有 Android 设备上都适用的答案;这个答案可以在大多数设备上使用,但在三星 S4 上无法正常工作。设备碎片化万岁! - Glorfindel
@xmen OP 询问如何删除一张图片,而不是一个文件夹。如果要删除一个目录,我建议更深入地了解ContentProviderOperation。 - Tanner Perrien
通过内容提供程序删除项目也会将其删除,但仅适用于特定版本的Android。因此,对于旧版本的Android,您仍需要使用File.delete方法! - user924
显示剩余3条评论

24
File file = new File(photoUri);
file.delete();

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(photoUri))));

这段代码对我有效,我认为它比使用Intent.ACTION_MEDIA_MOUNTED重新挂载整个SD卡更好。


好的答案。我用它来解决我的问题 http://stackoverflow.com/a/26519238/1621111 - Konstantin Konopko
这绝对是最好的解决方案,除非在将内容插入内容解析器时跟踪其ID。它似乎比通过 getContentResolver().delete 查询内容解析器以获取内容ID,然后进行删除更快。 - sixones

19

删除图片:

ContentResolver contentResolver = getContentResolver();
contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            MediaStore.Images.ImageColumns.DATA + "=?" , new String[]{ imagePath });

这是唯一真正的答案,它删除图像文件并从媒体存储中删除条目,以便图像不会显示在MTP上。 - tingyik90
1
简单易用,适用于Android P...如果您将图像替换为视频,则也可以将其用于视频内容。 - Billy
只是为了澄清,这将删除SQL DATA字段,将MediaStore指向该文件,您仍然必须file.delete()它。一个操作可能失败,而另一个操作成功。 - Bonatti

5
在 Kotlin 中,您可以这样做:
private fun deleteImage(path: String) {
    val fDelete = File(path)
    if (fDelete.exists()) {
        if (fDelete.delete()) {
            MediaScannerConnection.scanFile(this, arrayOf(Environment.getExternalStorageDirectory().toString()), null) { path, uri ->
                Log.d("debug", "DONE")
            }
        } 
    }
}

非常适用于compileSdk 32!非常感谢! - The_Long_Distance_Runner

5

我尝试了所有这些解决方案,但在Android 6中没有成功。
最终,我发现这段代码片段可以很好地解决问题。

public static void deleteFileFromMediaStore(final ContentResolver contentResolver, final File file) {
    String canonicalPath;
    try {
        canonicalPath = file.getCanonicalPath();
    } catch (IOException e) {
        canonicalPath = file.getAbsolutePath();
    }
    final Uri uri = MediaStore.Files.getContentUri("external");
    final int result = contentResolver.delete(uri,
            MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
    if (result == 0) {
        final String absolutePath = file.getAbsolutePath();
        if (!absolutePath.equals(canonicalPath)) {
            contentResolver.delete(uri,
                    MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
        }
    }
}

我也在Android 4.4和5.1上进行了测试,结果完美无缺。


我正在删除一些媒体文件(图片和视频)。上面的代码对于每个媒体文件从媒体库中删除的时间太长了。在176毫秒内只能删除5个文件。我该如何加快速度? - hasnain_ahmad

4
sendBroadcast(new Intent(
           Intent.ACTION_MEDIA_MOUNTED,
           Uri.parse("file://" +  Environment.getExternalStorageDirectory())));

这段代码可以运行,但资源开销很大。它会卸载再挂载SD卡,可能会影响某些应用程序或消耗大量系统资源以刷新图库。我正在寻找更好的替代方法,如果找到了就会发布。


1
我遇到了同样的问题,尝试了三种不同的方法来删除一张图片。有时它可以工作,有时它不能。现在,经过太多时间的花费,我拥有的每种方法都可以删除这张图片。我的意思是:处理位图时要小心。我会先拍照并保存它,然后根据需要旋转:
public static Bitmap rotatePictureToPortraitMode(String filePath, Bitmap myBitmap) {
try {
    ExifInterface exif = new ExifInterface(filePath);
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
    Log.d("EXIF", "Exif: " + orientation);
    Matrix matrix = new Matrix();
    if (orientation == 6) {
        matrix.postRotate(90);
    } else if (orientation == 3) {
        matrix.postRotate(180);
    } else if (orientation == 8) {
        matrix.postRotate(270);
    }
    myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
} catch (Exception e) {

}
return myBitmap;
}

在此之后,我尝试删除图像,但正如我之前所说,它没有起作用。删除这个方法帮助我解决了问题。
也许这只是我的问题,但是一旦我删除了它,它帮助了我很多,所以我想说要小心处理图像。对于我的情况,我使用了先前提到的答案:
File file = new File(photoUri);
file.delete();

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
Uri.fromFile(new File(photoUri)))); 

希望它有所帮助!

0

DocumentFile.fromSingleUri(context, uri).delete();

对我来说运行得很好。


0

这些方法在Android 11+中已经过时, 要删除Android11+中的任何媒体文件,您可以发送删除请求。 为此,我找到了一个依赖项,请检查,我希望您的问题可以使用此方法解决。

https://github.com/jcredking/Delete1


请在您的回答中提供代码。 - Behnam Maboudi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接