繁体   English   中英

如何删除 Android 10 Scoped Storage 中的图像(媒体存储条目和文件)

[英]How to delete an Image in Android 10 Scoped Storage (Mediastore Entry & File)

当我尝试删除由我的应用程序提供/拥有的图像时,它可以轻松删除。 但是对于我的应用程序不拥有的图片文件夹中的共享媒体,我通过捕获RecoverableSecurityException向用户显示提示。 但即使在ALLOWING之后,我也无法删除该特定图像文件。

这是我正在使用的代码,请指出我做错了什么。

  • 删除后图像不会出现在图库或我的应用程序中,但它保留在文件管理器中并在手机重新启动后出现在图库中(我猜只有 MediaStore 条目被删除)
  • 该代码适用于 Android 11 设备。
  • 结果来自startIntentSenderForResult(intentSender, 12, null, 0, 0, 0, null); 结果正常

用于获取文件:(此代码在我的活动中)

   try {
            String DIRECTORY_NAME = "%Pictures/App_Name%";
            String selection = MediaStore.MediaColumns.RELATIVE_PATH + " like ? ";
            String[] selectionArgs = new String[]{DIRECTORY_NAME};
            ContentResolver contentResolver = this.getContentResolver();
            Cursor cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, selection, selectionArgs, null);

            while(cursor.moveToNext()){
                long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
                Uri contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);

                uriArrayList.add(contentUri);

            }
            cursor.close();
        }
        catch (Exception e){
            e.printStackTrace();
        }

用于删除图像文件:(此代码在我的 Adapter 类中)

    try {
    ContentResolver contentResolver = context.getContentResolver();
    cachedUri = f; //f is Uri 
    contentResolver.delete(f, null, null);
}catch (SecurityException securityException) {

    RecoverableSecurityException recoverableSecurityException;
    if (securityException instanceof RecoverableSecurityException) {
        recoverableSecurityException =
                (RecoverableSecurityException) securityException;
    } else {
        throw new RuntimeException(
                securityException.getMessage(), securityException);
    }
  
    IntentSender intentSender = recoverableSecurityException.getUserAction()
            .getActionIntent().getIntentSender();
    try {
        resultInterface.onResultTaken(intentSender, cachedUri); //Giving a call to the activity that implements the interface

    } catch (Exception e) {
        e.printStackTrace();
    }
}

提示用户(在我的活动中获取 onActivityResult):

public class SomeActivity extends AppCompatActivity implements ResultTakenListener{

protected void onCreate(){ 
...}

@Override
public void onResultTaken(IntentSender intentSender, Uri uri) throws IntentSender.SendIntentException {
    cacheduri = uri;
    startIntentSenderForResult(intentSender, 12, null, 0, 0, 0, null);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 12){
    Log.d("Result Code is-->", String.valueOf(resultCode)); //This gives RESULT_OK
        if(resultCode == RESULT_OK){
            ContentResolver contentResolver = this.getContentResolver();
            contentResolver.delete(cacheduri, null, null);
    
        }
    }
}}

我尚未对其进行测试,但我认为当您处理低于 Q 的构建时,您需要集成自定义行为。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                
         //your existing code that seems to work above Q
            } else {
                String docsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
                File file = new File(docsDir, "fileName.jpg");
                if(file.exists());
                file.delete();
            }

在您的 android 清单中添加android:requestLegacyExternalStorage="false" 这允许范围存储。

对于 android 10 以下的版本,将android:requestLegacyExternalStorage设置为false

好。 有2种方法可以做到。 其中之一也适用于 android 11。 我不是在这里谈论requestLegacyExternalStorage权限。 你也可以这样做,顺便说一句。

在 Android 10 中,如果您不使用requestLegacyExternalStorage权限或Storage Access Framework (DocumentsProvider way)则必须为每个文件获取删除文件权限。

为此,请检查此方法。

对于安卓 10:

public static void deleteImageAPI29(Context context, Uri uri) {
    ContentResolver resolver = context.getContentResolver();
    try {
        resolver.delete(uri, null, null);
    } catch (SecurityException securityException) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            RecoverableSecurityException recoverableSecurityException = (RecoverableSecurityException) securityException;
            IntentSenderRequest senderRequest = new IntentSenderRequest.Builder(recoverableSecurityException.getUserAction()
        .getActionIntent().getIntentSender()).build();
            deleteResultLauncher.launch(senderRequest);
        }
    }
}

现在, deleteResultLauncher在这里作为onActivityResult() API 替代品的替代品,因为它已从 android 11 中弃用。

这是您声明它的方式:

ActivityResultLauncher<IntentSenderRequest> deleteResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartIntentSenderForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                if (result.getResultCode() == RESULT_OK){
                    Toast.makeText(context, "Image deleted.", Toast.LENGTH_SHORT).show();
                }
            }
        }
);

它将提示一个对话框以删除图像。 如果用户允许,那么它将毫无问题地删除该图像。

对于安卓 11:

public void deleteImageAPI30(Context context, ArrayList<Media> arrayList) {
    ContentResolver contentResolver = context.getContentResolver();
    ArrayList<Uri> arrayList2 = new ArrayList();
    for (int i = 0; i < arrayList.size(); i++) {
        arrayList2.add(arrayList.get(i).getUri()); // You need to use the Uri you got using ContentUris.withAppendedId() method
    }
    Collections.addAll(arrayList2);
    IntentSender intentSender = MediaStore.createDeleteRequest(contentResolver, arrayList2).getIntentSender();
    IntentSenderRequest senderRequest = new IntentSenderRequest.Builder(intentSender)
            .setFillInIntent(null)
            .setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 0)
            .build();
    deleteResultLauncher.launch(senderRequest);
}

deleteResultLauncher的声明与上图相同。

第二种方法在这里更有用,因为它可用于一次删除多个图像。 但不幸的是,它从 Android 11 开始。它在 android 10 中不可用。因此,如果您想在 android 10 中删除多个图像,那么您可以使用requestLegacyExternalStorage选项或“DocumentsProvider”API。

除此之外,这两种方法非常适合这个原因。

是的,如果您想使用Mediastore API保存 Android 10 及以上版本中的图像,请查看本文,它将对您有很大帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM