![](/img/trans.png)
[英]FileSystemException: Cannot open file, path = 'Directory: '/storage/emulated/0/Android/data/
[英]Android - Unable to open content: file:///storage/emulated/0
我有一个带有九个补丁图像背景的小部件。 图像保存在 /sdcard/mydir/bgs 中。
当我尝试使用 setImageViewUri 方法加载图像时,出现此错误:
Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs
..
然后
...
open failed: EACCES (Permission denied)
这仅出现在主屏幕上,并且仅适用于 Nexus 10 和 Nexus 7(最新的启动器 4.4 不存在此错误)。 我的应用程序上也有一些 RemoteViews,并且一切正常。
我还在清单中添加了 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE。
我该如何解决?
更新:我检查了 setImageViewUri 方法,发现它改变了我的文件的路径。
if (value != null) {
// Resolve any filesystem path before sending remotely
value = value.getCanonicalUri();
if (StrictMode.vmFileUriExposureEnabled()) {
value.checkFileUriExposed("RemoteViews.setUri()");
}
}
此方法接收我的值 (/sdcard/mydir/bgs) 并将其更改为 (storage/emulated/0/sdcard/mydir/bgs)。 但是这个文件不存在通过 adb 进入系统。
与 Lollipop 一样,Google 引入了一种新方法,可以明确授予应用程序您希望它们在您的设备上使用的权限,并禁用您想要拒绝该应用程序的应用程序。 如果您注意到,在您的 android 监视器中,日志会显示
java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)
EACCESS permission denied
是 java 臭名昭著的FileNotFoundException
的原因。
要解决此问题,只需转到您的应用权限并为您的应用启用存储
你需要
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
在你的清单中。
看来setImageViewUri
与 file:// uris 一起使用不再安全。
为什么?
Jellybean 引入了READ_EXTERNAL_STORAGE
权限。 想要从外部存储读取的应用程序必须持有此权限。 在 KitKat 之前,默认情况下没有强制执行此操作。
启动器不持有此权限。 事实上,您不能保证您附加到的任何 RemoteView 都拥有该权限。 这使得使用 setImageViewUri 变得不安全,因为您不知道远程图像视图是否能够读取给定的 uri。
现在怎么办?
选项 1:使用 setImageViewBitmap。
由于活页夹交易失败,您可能已放弃此选项。 这些技巧只是确保您的图像小于 1 MB。 这并不像听起来那么难。 您可以准确计算图像的大小。 例如,如果您使用的是 ARGB_8888 图像,这意味着每个像素需要 4 个字节。 我们可以通过以下方式计算最大尺寸:
1 Mb = 1048576 字节 = 262144 像素 = 512 x 512 图像
当然,您可以使用 RGB_565 从中挤出更多,以获得 2 倍的像素。
另请注意,如果您的小部件很小,您可能不需要大图像。 您的 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);
请注意,返回的值是倾角而不是像素,因此您需要将它们转换为缩放位图。
选项 2:使用内容提供者
如果由于某种原因您仍然不喜欢 IPC 限制,您可以随时构建自定义内容提供程序。 将该 uri 传递到 setImageViewUri 中,您应该可以开始了。
路径切换呢?
路径切换不是真正的问题。 看起来这是一个问题,但仿真实际上工作正常。 尝试在//storage/emulated/0/sdcard/mydir/bgs
中创建一个文件,该文件将创建得很好。
您会注意到,虽然异常是 FileNotFoundException,但消息是 Permission Denied。
我认为您正在手动输入 SD 卡路径。 您应该获得如下存储路径,而不是手动输入 SD 卡路径:
File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.