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

Android 12下连续调用SAF创建文件仅首个生效问题求助

问题:Android连续启动SAF选择器写入文件仅首个成功

我们正在开发一款Android应用,需要连续执行文件写入操作,但连续启动SAF(Storage Access Framework)选择器并写入文件时,仅首个文件写入成功,后续文件无法写入。

期望实现目标

希望能连续启动SAF选择器并完成所有文件的写入操作,确保全部文件正常生成。

相关源码

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

        (0..2).forEach {
            val intent = Intent().apply {
                type = "*/*"
                action = Intent.ACTION_CREATE_DOCUMENT
                putExtra(Intent.EXTRA_TITLE, "test$it.txt")
                putExtra(
                    DocumentsContract.EXTRA_INITIAL_URI,
                    Uri.parse("content://com.android.externalstorage.documents/document/primary%3ADownload")
                )
            }
            testFileCreate.launch(intent)
        }
    }

    private val testFileCreate = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        try {
            contentResolver.openOutputStream(result.data?.data!!) .use { outputStream ->
                outputStream?.write("testdata".toByteArray())
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

已尝试方案

  • 单独逐个启动并关闭SAF选择器时操作正常,但在上一个SAF选择器未关闭时启动下一个,仅首个文件能成功创建。
  • 使用ActivityResultContracts.OpenDocumentTree()可实现需求,但Android 12中该方法无法访问Download文件夹;同时因审核及稳定性考量,不使用MANAGE_EXTERNAL_STORAGE权限。

补充信息

系统版本:Android 12


解决方案

问题原因

连续调用launch()启动SAF选择器时,Android系统只会处理第一个启动请求,后续请求会被直接忽略——因为同一时间只能有一个Activity启动请求处于活跃状态,前一个未完成时,新的启动请求不会被系统调度。

实现思路

改成串行处理:完成一个文件的SAF选择与写入后,再启动下一个SAF选择器。通过维护待处理任务队列,在每次ActivityResult回调完成后,从队列中取出下一个任务执行。

修改后的代码

class MainActivity : AppCompatActivity() {
    // 维护待创建的文件名称队列
    private val fileNames = mutableListOf("test0.txt", "test1.txt", "test2.txt")
    private val testFileCreate = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        try {
            result.data?.data?.let { uri ->
                contentResolver.openOutputStream(uri).use { outputStream ->
                    outputStream?.write("testdata".toByteArray())
                }
            }
            // 当前文件处理完成后,启动下一个
            startNextFileCreate()
        } catch (e: Exception) {
            e.printStackTrace()
            // 即使出错,也继续处理下一个文件
            startNextFileCreate()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 启动第一个文件的创建流程
        startNextFileCreate()
    }

    private fun startNextFileCreate() {
        if (fileNames.isNotEmpty()) {
            val fileName = fileNames.removeAt(0)
            val intent = Intent().apply {
                type = "*/*"
                action = Intent.ACTION_CREATE_DOCUMENT
                putExtra(Intent.EXTRA_TITLE, fileName)
                putExtra(
                    DocumentsContract.EXTRA_INITIAL_URI,
                    Uri.parse("content://com.android.externalstorage.documents/document/primary%3ADownload")
                )
            }
            testFileCreate.launch(intent)
        }
    }
}

代码说明

  1. 用fileNames列表存储所有需要创建的文件名,作为任务队列。
  2. startNextFileCreate()方法负责从队列头部取出文件名,创建SAF启动意图并调用launch()。
  3. 在ActivityResult回调中,完成当前文件的写入后,立即调用startNextFileCreate()启动下一个任务,实现串行处理。
  4. 即使某个文件处理出错,也会继续处理下一个文件,避免全部流程中断。

额外提示

SAF的ACTION_CREATE_DOCUMENT不支持批量创建文件,只能通过串行逐个处理的方式实现连续写入需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:55:18