【问题标题】:Android 6.0: SD Card Directory creation fails in spite of having permissionsAndroid 6.0:尽管有权限,但 SD 卡目录创建失败
【发布时间】:2017-08-23 18:40:31
【问题描述】:

我正在尝试创建一个外部目录结构,以便将一些文件从设备存储移动到 Android 手机中的 SD 卡。我已按照https://developer.android.com/training/permissions/requesting.html 和多个stackoverflow 答案中给出的步骤进行操作。但是,当我尝试创建目录时,我的程序失败了。

我的AndroidManifest.xml 文件包含以下几行:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

相关代码如下:

    public int mkFolder(String folderName){
        String state = Environment.getExternalStorageState();
        if (!Environment.MEDIA_MOUNTED.equals(state)){
            Log.d(TAG, "Error: external storage is unavailable");
            return 0;
        }
        if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            Log.d(TAG, "Error: external storage is read only.");
            return 0;
        }
        Log.d(TAG, "External storage is not read only or unavailable");

        boolean writePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
        boolean readPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
        final boolean permissionNotGranted = writePermission|| readPermission;
        if (permissionNotGranted) {
            Log.i(TAG, "STORAGE permissions NOT granted");
            // Should we show an explanation?
            boolean shouldShowRationaleForWritePermssion = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
            boolean shouldShowRationaleForReadPermssion = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE);
            if (shouldShowRationaleForWritePermssion || shouldShowRationaleForReadPermssion) {

                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

            } else {
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } else {
            Log.i(TAG, "STORAGE permissions granted");
        }

//        File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),folderName);
        File folder = new File(folderName);
        int result = 0;
        if (folder.exists()) {
            Log.d(TAG,"folder exist:"+folder.toString());
            result = 2; // folder exist
        }else{
            try {
                if (folder.mkdirs()) {
                    Log.d(TAG, "folder created:" + folder.toString());
                    result = 0; // folder created
                } else {
                    Log.d(TAG, "create folder fails:" + folder.toString());
                    result = 1; // create folder fails
                }
            }catch (Exception ecp){
                ecp.printStackTrace();
            }
        }
        return result;
    }

    public static final int REQUEST_EXTERNAL_STORAGE = 112;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[], @NonNull int[] grantResults) {
        Log.e(TAG, "onRequestPermissionsResult invoked");
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    Log.i(TAG, "Permission to write to external storage granted");
                    Toast.makeText(this, "Permission to write to external storage granted", Toast.LENGTH_LONG).show();
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Log.e(TAG, "Permission to write to external storage NOT granted");
                    Toast.makeText(this, "Permission to write to external storage NOT granted", Toast.LENGTH_LONG).show();
                }
            }
            // other 'case' lines to check for other
            // permissions this app might request
        }
    }

以下是日志的摘录:

MainActivity: /storage/0000-0000    false   true
MainActivity: /storage/0000-0000/MyDir does not exist. Creating target parent directory
MainActivity: STORAGE permissions granted
MainActivity: Creation of directory /storage/0000-0000/MyDir failed with return value 1. Aborting...

谁能帮我理解我的代码中的错误是什么?

【问题讨论】:

    标签: android android-6.0-marshmallow


    【解决方案1】:

    从 Android 4.4 开始,您无法直接访问 removable storage 上的任意位置的文件系统。 WRITE_EXTERNAL_STORAGE 在这里毫无意义,因为external storage 不是可移动存储。

    改用存储访问框架(ACTION_OPEN_DOCUMENT_TREE 和 kin)。或者,将您的工作限制在作为getExternalFilesDirs()getExternalCacheDirs()getExternalMediaDirs()Context 上的所有方法)的一部分返回的可移动存储位置。

    【讨论】:

    • 感谢您的回答。这是否意味着我无法在 SD 卡的根目录创建目录?我见过其他一些应用程序(如短信备份和恢复类应用程序)在 SD 卡的“根”中创建目录。你知道其他方法可以做到这一点吗?
    • @KarthickS:通过存储访问框架,用户可以为您选择一个位置来创建文档树(目录)。这可能是某些可移动存储卷的根。它可能位于可移动存储卷的某个子目录中。它可能完全使用其他一些存储提供程序(例如,Google Drive)。存储访问框架的美妙之处在于您的应用程序不必关心。它只使用您返回的Uri,以及像DocumentFile 这样的支持类,然后您将内容放置在用户要求放置它的位置。
    • 非常感谢。这正是我想要的。作为 Android 编程的新手,我根本没有意识到存储访问框架的存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 2022-01-02
    相关资源
    最近更新 更多