android - 如何修复 contentResolver.openOutputStream(Uri) IllegalArgumentException:媒体是只读的?
问题描述
更新(重写)我的问题:
在 Android 11 上,我收到如下所示的错误(异常)。尝试保存在“最近”对话框中打开的文件会导致错误。如果我从 sdk_phone_x86 > 下载中选择相同的文件,则没有错误。返回的 Uri 的差异:
Recent:
content://com.android.providers.media.documents/document/document%3A33
filename: sample2.txt (size: 2894)
sdk_gphone_x86:
content://com.android.externalstorage.documents/document/primary%3ADownload%2Fsample2.txt
filename: sample2.txt (size: 2894)
Android 10 (API 29) 在这两种情况下保存文件都没有任何问题,即使 Uri 也不同:
API 29
Recent:
content://com.android.providers.downloads.documents/document/18
filename: sample2.txt (size: 2859)
Android SDK Built for x86:
content://com.android.externalstorage.documents/document/primary%3ADownload%2Fsample2.txt
filename: sample2.txt (size: 2859)
MainActivity.tk 重现问题:
https ://gist.github.com/s3va/85c1c330f9786c60903934d7e3e8f479
原始问题:
我正在尝试为小文本文件制作一个简单的编辑器。编辑文本视图。两个按钮。“加载文件”和“保存文件”。
只有一个活动或视图模型、片段和选项菜单。
private var uri: Uri? = null
private val resultContracts=registerForActivityResult(ActivityResultContracts.OpenDocument()){ u ->
if(u==null){
Toast.makeText(this, "No file selected", Toast.LENGTH_SHORT).show()
return@registerForActivityResult
}
uri=u
contentResolver.openInputStream(u)?.bufferedReader()?.use {
mEditTextView.setText(it.readText())
}
when (val p=checkUriPermission(uri,Binder.getCallingPid(),Binder.getCallingUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) {
PackageManager.PERMISSION_GRANTED ->
Toast.makeText(this, "Write Permission Granted.", Toast.LENGTH_LONG).show()
PackageManager.PERMISSION_DENIED ->
Toast.makeText(this, "Write Permission Denied!!!!", Toast.LENGTH_LONG).show()
else ->
Toast.makeText(this, "Down Know what is this permission: $p", Toast.LENGTH_LONG).show()
}
}
每当我打开文件时,我都会得到 Toast:“授予写入权限。”。这是检查记录是否可用的正确方法吗?文件总是成功加载到 EditText(var 或/和 TextView)中。然后我尝试将 EditText 的内容写入同一个 Uri。有时会出现以下异常:
2021-09-19 06:48:37.241 31926-31926/tk.kvakva.sevastexteditor E/AndroidRuntime: FATAL EXCEPTION: main
Process: tk.kvakva.sevastexteditor, PID: 31926
java.lang.IllegalArgumentException: Media is read-only
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:153)
at android.content.ContentProviderProxy.openAssetFile(ContentProviderNative.java:704)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1818)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:1520)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:1496)
at tk.kvakva.sevastexteditor.ui.open.OpenViewModel.savetext(OpenViewModel.kt:30)
at tk.kvakva.sevastexteditor.ui.open.OpenFragment.onOptionsItemSelected(OpenFragment.kt:118)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:3122)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:3226)
at androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:3126)
at androidx.fragment.app.FragmentManager.dispatchOptionsItemSelected(FragmentManager.java:3226)
at androidx.fragment.app.FragmentController.dispatchOptionsItemSelected(FragmentController.java:416)
at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:358)
at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:264)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:65)
at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:208)
at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:780)
at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:834)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:985)
at androidx.appcompat.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
at android.widget.AdapterView.performItemClick(AdapterView.java:330)
at android.widget.AbsListView.performItemClick(AbsListView.java:1210)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3202)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7697)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:952)
这段代码有什么问题?
findViewById<Button>(R.id.saveBtn).setOnClickListener {
uri?.let { u ->
contentResolver.openOutputStream(u)?.bufferedWriter()?.use { bufferedWriter ->
bufferedWriter.write(mEditTextView.text.toString())
}
}
}
我尝试在 Activity 的 onCreate() 中调用它。在选项菜单的片段中。在 Android 视图模型中。
有时它工作正常。文件已成功编辑。当我单击“保存”按钮时,有时会随机出现异常。我找不到导致错误的原因。它绝对不是只读媒体。在 var 和 TextView 和 EditText 中读取和加载文件时,它们实际上是由 Uris 找到的。
最后,当我将文件从计算机复制到 android(模拟器或真正的智能手机)时,我的行为有了一些规律性,错误消失了,一切都按预期工作。成功读取、编辑下载目录中保存的文本文件。
$ ../../Android/Sdk/platform-tools/adb push ~/qq.txt ./storage/emulated/0/Download
智能手机上的 Android 是 11,存在这个可怕的问题。Emulator API 30 修订版 10。不确定,但较低的修订版不受影响。或者我还没有抓住他们。
解决方案
推荐阅读
- mongodb - 尝试将 mongodb 与我的应用程序连接时出现错误
- r - 在 R 中对高于和低于特定阈值的值进行分组
- javascript - React-Router 不会将我从组件重定向
- android - 如何确保我不会继续向我的房间数据库输入数据
- javascript - MERN stack err.kind 表达式:从哪里来?
- sql - 自己获取名字和姓氏
- sql - 如何在 SQL 中获取 COUNT - 当您有 2 个 JOINS 和一个日期范围时
- javascript - Dropzone 不会排队超过一项
- java - 特殊标识符:serialVersionUID 和 serialPersistentFields
- neo4j - 如何在 Neo4J 上使用 Cypher 在两个列表上进行元素明智的添加