You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin开发:无法读取外部存储目录及文件问题求助

解决Android API26下无法读取外部存储目录的问题

针对你遇到的目录存在但无法读取、listFiles()返回null的问题,核心原因是权限请求未处理回调逻辑,加上可能的权限请求不完整,以下是具体解决步骤:

1. 补全权限请求的回调处理

你当前只发起了权限请求,但未处理用户授权后的操作。当用户点击允许权限后,需要在回调中重新执行文件读取逻辑。

2. 同时请求读写存储权限

虽然API23+中同一权限组的权限会被同时授予,但为了兼容性,建议同时请求READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。

3. 抽离文件读取逻辑,避免重复代码

将读取文件的代码封装成独立方法,方便在权限校验通过和回调成功时复用。

修改后的完整代码示例

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    if (checkPermission()) {
        loadFiles()
    } else {
        requestPermission()
    }

    if (savedInstanceState == null) {
        supportFragmentManager.beginTransaction()
                .replace(R.id.container, MainFragment.newInstance())
                .commitNow()
    }
}

// 检查读写权限是否都已授予
private fun checkPermission(): Boolean {
    val readGranted = ContextCompat.checkSelfPermission(
        this,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ) == PackageManager.PERMISSION_GRANTED
    val writeGranted = ContextCompat.checkSelfPermission(
        this,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    ) == PackageManager.PERMISSION_GRANTED
    return readGranted && writeGranted
}

// 请求读写存储权限
private fun requestPermission(){
    val shouldShowRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) ||
            ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    
    if(shouldShowRationale){
        Toast.makeText(this, "需要存储权限来访问文件", Toast.LENGTH_SHORT).show()
    } else {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ),
            111
        )
    }
}

// 处理权限请求结果
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if(requestCode == 111){
        if(grantResults.isNotEmpty() && grantResults.all { it == PackageManager.PERMISSION_GRANTED }){
            loadFiles()
        } else {
            Toast.makeText(this, "存储权限被拒绝,无法访问文件", Toast.LENGTH_SHORT).show()
        }
    }
}

// 封装文件读取逻辑
private fun loadFiles(){
    val rootDir = Environment.getExternalStorageDirectory()
    Log.d("FILETAG", "路径: ${rootDir.path}")
    Log.d("FILETAG", "是否存在: ${rootDir.exists()}")
    Log.d("FILETAG", "是否可读: ${rootDir.canRead()}")
    
    val filesAndFolders = rootDir.listFiles()
    if(filesAndFolders != null){
        Log.d("FILETAG", "文件/文件夹数量: ${filesAndFolders.size}")
        // 将数据传递给Fragment,可通过ViewModel或接口回调
        // 示例(假设使用ViewModel):
        // yourViewModel.updateFiles(filesAndFolders.toList())
    } else {
        Log.e("FILETAG", "无法列出文件,目录不可读")
    }
}

针对Fragment的补充说明

如果需要在Fragment中实现读取逻辑,可以直接在Fragment内处理权限请求和文件读取:

  • 在Fragment中使用requestPermissions()方法发起请求
  • 重写Fragment的onRequestPermissionsResult()处理回调
  • 确保Fragment和Activity的权限请求逻辑保持一致,避免冲突

内容的提问来源于stack exchange,提问作者Phoenonical

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:40:35