应用程序在Android 10上崩溃?

时间:2020-03-04 09:40:27

标签: android illegalstateexception

我的应用程序在Play商店上使用了2年,并且运行良好。但是在过去的两周内,突然有用户报告说应用程序在使用时崩溃了。

所有崩溃均适用于Android 10用户。

织品日志显示错误为

java.lang.IllegalStateException: Only owner is able to interact with pending media content://media/external/images/media/259525
        at android.os.Parcel.createException(Parcel.java:2079)
        at android.os.Parcel.readException(Parcel.java:2039)
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:188)
        at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151)
        at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:705)
        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1687)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1503)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1420)
        at android.graphics.ImageDecoder$ContentResolverSource.createImageDecoder(ImageDecoder.java:277)
        at android.graphics.ImageDecoder.decodeDrawableImpl(ImageDecoder.java:1743)
        at android.graphics.ImageDecoder.decodeDrawable(ImageDecoder.java:1736)
        at android.widget.ImageView.getDrawableFromUri(ImageView.java:1022)
        at android.widget.ImageView.resolveUri(ImageView.java:991)
        at android.widget.ImageView.setImageURI(ImageView.java:568)
        at androidx.appcompat.widget.AppCompatImageView.setImageURI(AppCompatImageView.java:116)
        at androidx.databinding.adapters.ImageViewBindingAdapter.setImageUri(ImageViewBindingAdapter.java:46)

此屏幕上发生的事情是,用户应该捕获一个屏幕截图。我保存此屏幕截图,并稍后在ImageView上显示。我通过URI来获取屏幕截图。

当我使用URI 检索图像时,发生崩溃。

  1. App Compile SDK版本:28
  2. App Target SDK版本:28

2 个答案:

答案 0 :(得分:4)

让我解释一下您收到此异常的确切原因以及如何解决它

但首先,请仔细记住您的错误信息

<块引用>

“只有所有者才能与待处理的媒体进行交互 content://media/external/images/media/259525"

请记住“owner”这个词,在后面的解释中你会知道这个词的意义。

我是如何遇到这个异常的:

我正在开发一个已经在 Play 商店上线的 pdf 阅读器应用程序。 我们也从 crashlytics 得到了同样的异常。就像您的情况一样,大多数设备都是 Android 10。

为什么在我的情况下会发生此异常

一些用户过去常常做的是, 他们会开始从网络下载pdf文件, 然后他们会意识到,pdf文件太大了, 然后他们会暂停 pdf 下载(也许稍后下载), 然后他们会转到文件管理器并尝试使用我的应用程序打开部分下载的 pdf 文件。 此时,由于 pdf 已部分下载,我的应用程序将在 openInputStream() 方法上崩溃(就像您在 openAssetFileDescriptor() 时崩溃一样)

“所有者”一词的意义:

“所有者”一词在这里非常重要。让我来告诉你为什么。 就我而言,最终用户过去常常使用下载管理器(在 chrome 中)下载 pdf。因此,下载管理器需要从网络上获取文件包,重新组装它们并重新创建原始文件。现在,只要文件没有完全下载并重新组装,下载管理器就会保留该文件的“所有者”。这意味着文件将被同步进程锁定,只有下载管理器才有权释放锁定。因此,当文件完全下载后,chrome 将释放对该文件的锁定,并且所有其他应用程序都可以访问该文件。

我是如何解决崩溃的:

我用 try-catch 块包围了错误行。如果我收到 IllegalStateException,我会向用户展示文件部分下载或损坏 我做了这样的事情

    try{
        try (InputStream in = getContentResolver().openInputStream(uri);)
        {
                 -------
                 -------
        } catch (IOException | SecurityException e) {
                Timber.e(e, "Could not save work file");
                finishError(getString(R.string.mopria_document_reading_error));
        }
    }catch(IllegalStateException exception){
            Toast.makeText(getApplicationContext(), "The file is either partially 
                     downloaded or corrupted", Toast.LENGTH_LONG).show();
            finishAndRemoveTask();
        }

为什么主要使用 Android 10:

该问题不仅限于 android 10。巧合的是 android 为大多数服务(如 chrome、google 文件等)推出了更新,允许其他应用查看这些部分创建的文件。

就您而言:

屏幕截图将由android的屏幕截图管理器捕获(我不记得确切的名称)。因此,只要将捕获的屏幕截图保存到存储中,您将无法获得屏幕截图。在较新的 android 版本中,当捕获屏幕截图时,您将快速预览该屏幕截图。除非预览结束,否则屏幕截图管理器将成为该文件的所有者。

答案 1 :(得分:0)

将文件提供程序用于图像URI。

尝试此代码:

添加代码AndroidManifest.xml

<application>
  <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.mypackage.myprovider"
    android:exported="false"
    android:grantUriPermissions="true">
   <meta-data
     android:name="android.support.FILE_PROVIDER_PATHS"
     android:resource="@xml/provider_paths"/>
  </provider>
</application>

在res下的xml文件夹中添加provider_paths.xml文件。

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <external-path name="external_files" path="."/>
</paths>

从活动类的底部代码获取uri。

final Uri data = FileProvider.getUriForFile(context, "myprovider", new File(file_path)); //here your image uri