Android SAF(存储访问框架):从 TreeUri 获取特定文件 Uri [英] Android SAF (Storage Access FrameWork): Get particular file Uri from TreeUri

查看:45
本文介绍了Android SAF(存储访问框架):从 TreeUri 获取特定文件 Uri的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在获取外部 Sd 卡的 PersistableUriPermission 并将其存储以供进一步使用.现在我希望当用户从我的应用程序中的文件列表中向我提供文件路径时,我想编辑文档并重命名它.

I am taking External Sd Card's PersistableUriPermission and storing it for further use. Now I want that when user provides me with the file path, from list of files in my application, I want to edit the document and rename it.

所以我有要编辑的文件的文件路径.

So I have the file path of the file to edit.

我的问题是如何从我的 TreeUri 中获取该文件的 Uri 作为编辑文件.

My question is how do I get that file's Uri from my TreeUri so as edit file.

推荐答案

访问 Sd-Card 的文件

使用DOCUMENT_TREE对话框获取sd卡的Uri.

Use DOCUMENT_TREE dialog to get sd-card's Uri.

告知用户如何在对话框中选择sd-card.(附图片或gif动画)

Inform the user about how to choose sd-card on the dialog. (with pictures or gif animations)

// call for document tree dialog
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE);

onActivityResult 上,您将拥有所选目录Uri.(sdCardUri)

On onActivityResult you'll have the selected directory Uri. (sdCardUri)

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CODE_OPEN_DOCUMENT_TREE:
            if (resultCode == Activity.RESULT_OK) {
                sdCardUri = data.getData();
             }
             break;
     }
  }

现在必须检查用户,

一个.选择了 SD 卡

a. selected the sd-card

B.选择了文件所在的 SD 卡(某些设备可能有多个 SD 卡).

b. selected the sd-card that our file is on (some devices could have multiple sd-cards).

我们通过从 sd root 到我们的文件的层次结构查找文件来检查 a 和 b.如果找到文件,则获取a和b条件.

We check both a and b by finding the file through the hierarchy, from sd root to our file. If the file found, both of a and b conditions are acquired.

//First we get `DocumentFile` from the `TreeUri` which in our case is `sdCardUri`.
DocumentFile documentFile = DocumentFile.fromTreeUri(this, sdCardUri);

//Then we split file path into array of strings.
//ex: parts:{"", "storage", "extSdCard", "MyFolder", "MyFolder", "myImage.jpg"}
// There is a reason for having two similar names "MyFolder" in 
//my exmple file path to show you similarity in names in a path will not 
//distract our hiarchy search that is provided below.
String[] parts = (file.getPath()).split("\/");

// findFile method will search documentFile for the first file 
// with the expected `DisplayName`

// We skip first three items because we are already on it.(sdCardUri = /storage/extSdCard)
for (int i = 3; i < parts.length; i++) {
    if (documentFile != null) {
        documentFile = documentFile.findFile(parts[i]);
    }
  }

if (documentFile == null) {

    // File not found on tree search
    // User selected a wrong directory as the sd-card
    // Here must inform the user about how to get the correct sd-card
    // and invoke file chooser dialog again.  

    // If the user selects a wrong path instead of the sd-card itself,  
    // you should ask the user to select a correct path.  
    // I've developed a gallery app with this behavior implemented in it.  
    // https://play.google.com/store/apps/details?id=com.majidpooreftekhari.galleryfarsi
    // After you installed the app, try to delete one image from the  
    // sd-card and when the app requests the sd-card, select a wrong path  
    // to see how the app behaves.  

 } else {

    // File found on sd-card and it is a correct sd-card directory
    // save this path as a root for sd-card on your database(SQLite, XML, txt,...)

    // Now do whatever you like to do with documentFile.
    // Here I do deletion to provide an example.


    if (documentFile.delete()) {// if delete file succeed 
        // Remove information related to your media from ContentResolver,
        // which documentFile.delete() didn't do the trick for me. 
        // Must do it otherwise you will end up with showing an empty
        // ImageView if you are getting your URLs from MediaStore.
        // 
        Uri mediaContentUri = ContentUris.withAppendedId(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                longMediaId);
        getContentResolver().delete(mediaContentUri , null, null);
    }


 }

我的应用程序上错误的 SD 卡路径选择行为:

要检查错误的 sd 卡路径选择的行为,请安装应用程序并尝试删除 sd 卡上的图像并选择错误的路径而不是 sd 卡目录.
日历库:https://play.google.com/store/应用程序/详细信息?id=com.majidpooreftekhari.galleryfarsi

To check the behavior on the wrong sd-card path selection install the app and try to delete an image that is on your sd-card and select a wrong path instead of your sd-card directory.
Calendar Gallery: https://play.google.com/store/apps/details?id=com.majidpooreftekhari.galleryfarsi

注意:

您必须提供对清单内外部存储和应用程序内 os>=Marshmallow 的访问权限.https://stackoverflow.com/a/32175771/2123400

You must provide access permission to the external storage inside your manifest and for os>=Marshmallow inside the app. https://stackoverflow.com/a/32175771/2123400

编辑 SD 卡的文件

要编辑 sd 卡上的现有图像,如果您想调用另一个应用程序来为您执行此操作,则不需要上述任何步骤.

For editing an existing image on your sd-card you don't need any of the above steps if you want to invoke another app to do it for you.

在这里,我们调用具有编辑图像功能的所有活动(来自所有已安装的应用程序).(程序员在清单中标记他们的应用,因为它具有提供来自其他应用(活动)的可访问性的能力).

Here we invoke all the activities (from all the installed apps) with the capability of editing the images. (Programmers mark their apps in the manifest for its capabilities to provide accessibility from other apps (activities)).

在您的 editButton 点击​​事件上:

on your editButton click event:

String mimeType = getMimeTypeFromMediaContentUri(mediaContentUri);
startActivityForResult(Intent.createChooser(new Intent(Intent.ACTION_EDIT).setDataAndType(mediaContentUri, mimeType).putExtra(Intent.EXTRA_STREAM, mediaContentUri).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION), "Edit"), REQUEST_CODE_SHARE_EDIT_SET_AS_INTENT);

这是获取 mimeType 的方法:

and this is how to get mimeType:

public String getMimeTypeFromMediaContentUri(Uri uri) {
    String mimeType;
    if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
        ContentResolver cr = getContentResolver();
        mimeType = cr.getType(uri);
    } else {
        String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
                .toString());
        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                fileExtension.toLowerCase());
    }
    return mimeType;
}

注意:

在 Android KitKat(4.4) 上不要要求用户选择 sd 卡,因为在这个版本的 Android 上 DocumentProvider 不适用,因此我们没有机会访问 sd-用这种方法卡.查看 DocumentProvider 的 API 级别https://developer.android.com/reference/android/provider/DocumentsProvider.html
我找不到任何适用于 Android KitKat(4.4) 的东西.如果您发现 KitKat 有任何有用之处,请与我们分享.

On Android KitKat(4.4) don't ask the user to select the sd-card because on this version of Android DocumentProvider is not applicable, hence we have no chance to have access to the sd-card with this approach. Look at the API level for the DocumentProvider https://developer.android.com/reference/android/provider/DocumentsProvider.html
I couldn't find anything that works on Android KitKat(4.4). If you found anything useful with KitKat please share it with us.

在 KitKat 以下的版本上,操作系统已经提供了对 SD 卡的访问.

On versions below the KitKat access to sd-card is already provided by the OS.

这篇关于Android SAF(存储访问框架):从 TreeUri 获取特定文件 Uri的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆