首页 > 解决方案 > 如何修复 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。不确定,但较低的修订版不受影响。或者我还没有抓住他们。

标签: androidkotlinandroid-contentresolver

解决方案


推荐阅读