Android - 无法打开内容:file:///storage/emulated/0

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20631446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:10:56  来源:igfitidea点击:

Android - Unable to open content: file:///storage/emulated/0

androidwidgetnine-patch

提问by CeccoCQ

I've a widget with nine-patch image background. The image was saved in /sdcard/mydir/bgs.

我有一个带有九个补丁图像背景的小部件。图像保存在 /sdcard/mydir/bgs 中。

When I try to load a image with setImageViewUri method, I've this error:

当我尝试使用 setImageViewUri 方法加载图像时,出现以下错误:

Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs

..

..

then

然后

...

...

open failed: EACCES (Permission denied)

This appears only on the the home screen and only with Nexus 10 and Nexus 7 (with latest launcher 4.4 this bug not exist). I've also have some RemoteViews on my application and all works correctly.

这仅出现在主屏幕上,并且仅适用于 Nexus 10 和 Nexus 7(最新的启动器 4.4 不存在此错误)。我的应用程序上也有一些 RemoteViews,并且一切正常。

I've also added into manifest either READ_EXTERNAL_STORAGE, either WRITE_EXTERNAL_STORAGE.

我还在清单中添加了 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE。

How can I solve?

我该如何解决?

UPDATE: I've inspect the method setImageViewUri and I've found that it changes the path of my file.

更新:我检查了 setImageViewUri 方法,发现它改变了我的文件路径。

if (value != null) {
            // Resolve any filesystem path before sending remotely
            value = value.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                value.checkFileUriExposed("RemoteViews.setUri()");
            }
        }

This method receive my value (/sdcard/mydir/bgs) and changes it into (storage/emulated/0/sdcard/mydir/bgs). But this file not exists into system via adb.

此方法接收我的值 (/sdcard/mydir/bgs) 并将其更改为 (storage/emulated/0/sdcard/mydir/bgs)。但是这个文件不存在通过 adb 进入系统。

采纳答案by Grimmace

It appears setImageViewUriis no longer safe to use with file:// uris.

setImageViewUri与 file:// uris 一起使用似乎不再安全。

Why?

为什么?

Jellybean introduced the READ_EXTERNAL_STORAGEpermission. Apps that want to read from external storage must hold this permission. This wasn't enforced by default until KitKat.

Jellybean 介绍了READ_EXTERNAL_STORAGE许可。想要从外部存储读取的应用程序必须持有此权限。默认情况下,直到 KitKat 才强制执行此操作。

The launcher does not hold this permission. In fact you are not guaranteed that any RemoteView you attach to holds that permission. This makes it unsafe to use setImageViewUri, since you don't know if the remote image view will even be able to read the given uri.

启动器不持有此权限。事实上,您不能保证附加到的任何 RemoteView 都拥有该权限。这使得使用 setImageViewUri 变得不安全,因为您不知道远程图像视图是否能够读取给定的 uri。

What now?

现在怎么办?

Option 1: Use setImageViewBitmap.

选项 1:使用 setImageViewBitmap。

You may have moved away from this option due to failed binder transactions. The trick to those is just making sure your image is under 1 MB. This isn't as hard as it sounds. You can calculate exactly how big your image is going to be. For instance if you are using an ARGB_8888 image that means you'll need 4 bytes per pixel. We can calulate the max size by:

由于活页夹交易失败,您可能已经放弃了此选项。解决这些问题的诀窍是确保您的图像小于 1 MB。这并不像听起来那么难。您可以准确计算出图像的大小。例如,如果您使用的是 ARGB_8888 图像,则意味着每个像素需要 4 个字节。我们可以通过以下方式计算最大尺寸:

1 Mb = 1048576 bytes = 262144 pixels = 512 x 512 image

1 Mb = 1048576 字节 = 262144 像素 = 512 x 512 图像

Of course you can squeeze more out of it using RGB_565 to get 2x the pixels.

当然,您可以使用 RGB_565 从中挤出更多,以获得 2 倍的像素。

Also note that you may not need a huge image if your widget is small. Your appwidget can ask about its specific options by the following:

另请注意,如果您的小部件很小,您可能不需要大图像。您的 appwidget 可以通过以下方式询问其特定选项:

Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetIds[i]);

int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);

int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);

Just be aware that the returned values are in dip not pixels so you will need to convert them to scale your bitmap.

请注意,返回的值是倾斜而不是像素,因此您需要将它们转换为缩放位图。

Option 2: Use a content provider

选项 2:使用内容提供程序

If for some reason you still don't like the IPC restriction, you can always build a custom content provider. Pass that uri into the setImageViewUri, and you should be good to go.

如果出于某种原因您仍然不喜欢 IPC 限制,您可以随时构建自定义内容提供程序。将该 uri 传递到 setImageViewUri 中,您应该很高兴。

What about the path switch?

路径切换呢?

The path switch is not the real issue. It looks like it is a problem, but the emulation actually works fine. Try creating a file inside //storage/emulated/0/sdcard/mydir/bgsand the file will create just fine.

路径切换不是真正的问题。看起来这是一个问题,但仿真实际上工作正常。尝试在里面创建一个文件//storage/emulated/0/sdcard/mydir/bgs,该文件将创建得很好。

You'll notice that while the exception is a FileNotFoundException the message is Permission Denied.

您会注意到,虽然异常是 FileNotFoundException,但消息是 Permission Denied。

回答by toniton

As from Lollipop, Google introduced a new way of explicitly giving apps the permission you want them to use on your device and disabling the ones you want to deny the app. If you notice, in your android monitor, the log shows

从 Lollipop 开始,Google 引入了一种新方法,可以明确授予应用程序您希望它们在您的设备上使用的权限,并禁用您想要拒绝该应用程序的应用程序。如果您注意到,在您的 android 监视器中,日志显示

java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)

EACCESS permission deniedis the cause of the java's infamous FileNotFoundException.

EACCESS permission denied是导致java声名狼藉的原因FileNotFoundException

To solve this, just goto your App permission and enable storage for your app

要解决此问题,只需转到您的应用权限并为您的应用启用存储

enter image description here

在此处输入图片说明

回答by Kuffs

You need

你需要

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

in your manifest.

在您的清单中。

回答by Vipul Purohit

I think you are entering SD card path manually. Instead of manually entering SD Card path you should get storage path like this :

我认为您正在手动输入 SD 卡路径。您应该获得如下存储路径,而不是手动输入 SD 卡路径:

File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";