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) } } }
代码说明
- 用
fileNames列表存储所有需要创建的文件名,作为任务队列。 startNextFileCreate()方法负责从队列头部取出文件名,创建SAF启动意图并调用launch()。- 在
ActivityResult回调中,完成当前文件的写入后,立即调用startNextFileCreate()启动下一个任务,实现串行处理。 - 即使某个文件处理出错,也会继续处理下一个文件,避免全部流程中断。
额外提示
SAF的ACTION_CREATE_DOCUMENT不支持批量创建文件,只能通过串行逐个处理的方式实现连续写入需求。
内容的提问来源于stack exchange,提问作者onsen
相关产品推荐
相关产品推荐

