Android R - 使用作用域存储(MediaStore.Downloads)在下载文件夹中创建文本文件

4
我的应用需要将一个字符串保存到“下载文件夹”中的文本文件中。目前(目标:API 29(Q)),我正在使用以下代码使用FILE API:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
android:requestLegacyExternalStorage="true"

但对于API 30(R),如果我理解正确,我需要将其迁移到Scoped存储(MediaStore.Downloads)。

在这里,我有点迷失了。我找不到好的文档或代码片段来展示如何在下载中创建文本文件。如果有人能够解释或展示如何操作,我将不胜感激。


1
只需先在“下载”文件夹中创建自己的目录,然后按照以往的方式将文件写入该目录即可。 - blackapps
谢谢,我会尝试这个解决方案,但我仍然有点糊涂。您的意思是如果我直接在/storage/emulated/Download中写入,它会失败吗?该目录是否应通过我的应用程序以编程方式创建?我可以使用标准的Java库来创建目录吗? - u2gilles
同时,您将尝试所有的内容,请汇报结果。 - blackapps
1个回答

5

刚刚在 AndrioidManifest.xml 中测试了您上面的设置:

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

在授予了这些权限并在运行API 30(R)的模拟器上,我能够使用以下简单代码编写/读取/更新文本文件:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    
    if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        val f = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "new_file.txt")
        f.appendText("test ${Instant.now().toEpochMilli()}\n")

        f.readLines().forEach { line -> Log.e("LOG", line)}
    }
}

这篇文章https://dev59.com/lr3pa4cB1Zd3GeqPgYye#64192581表明,如果您创建了文件,则可以使用File api访问它。注意:Environment.getExternalStoragePublicDirectory已被弃用,但似乎即使在Android 11上,如果您是文件的所有者,则仍然可以使用该方法。
只是为了好玩,我在目标和编译版本29/30之间交换,看看是否会因为针对不同的SDK并在同一模拟器上重新安装相同的应用程序而出现问题。结果很好,我可以完全访问相同的文件。
如果我说实话,整个过程有点混乱 - CommonsWare的这篇文章https://commonsware.com/blog/2019/12/21/scoped-storage-stories-storing-mediastore.html是一篇不错的阅读材料,因为它涉及到Android 11中现在强制执行的许多内容,尽管它大多谈论的是Android 10。
文档似乎分散在许多不同的地方,涉及存储/作用域存储等部分。这个链接指向一个表格,为根据初始用例筛选文档提供了很好的起点: https://developer.android.com/training/data-storage 我还附上了文件管理器中文件出现的截图:

File Manager

PS: 这里是一些糟糕的丢弃代码 - 输入/输出工作在主线程等等,仅供说明目的。

根据评论“R != 30”。我的“R”用法和Api“30”基于AndroidStudio IDE中的这个:

Andriod versions

(R = 运行环境,Api 30 = 运行时的sdk)
如果我有误解或在某些方面不符合语义要求,请随时进行编辑。

R!= 30。 R的行为更像是29。存在29、R和30。android:requestLegacyExternalStorage="true"只适用于29,并且对Android 11设备没有影响。 - blackapps
不,它不是假的。它没有影响。而且 R!=30 意味着 R 不等于 30。有 29、R 和 30,我再重复一遍。 - blackapps
谢谢大家,明天我会试着玩一下这个。 - u2gilles
1
Scoped storage enforcement 在 Android 11 上运行但目标为 Android 10(API 级别 29)的应用程序仍然可以请求 requestLegacyExternalStorage 属性。此标志允许应用程序暂时退出与作用域存储相关的更改,例如授予对不同目录和不同类型的媒体文件的访问权限。在将应用程序更新为针对 Android 11 的目标后,系统将忽略 requestLegacyExternalStorage 标志。 - Nahid Hasan
@NahidHasan 那反过来呢?我们有一个针对A11(API 30)的应用程序,可以在A10上运行。我发现它崩溃了,因为我们正在尝试使用旧方法getExternalStoragePublicDirectory(ourCustomFolder)。所以我们是否需要检查Build.VERSION.SDK_INT >= Build.VERSION_CODES.R或Q,以知道何时应该使用targetSdkVersion 30的Environment.DIRECTORY_DOCUMENTS? - JustAMartin
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接