且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2021-08-14 15:50:53

看来setImageViewUri与file://uris一起使用不再安全.

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

为什么?

Jellybean引入了READ_EXTERNAL_STORAGE权限.想要从外部存储读取的应用必须拥有此权限.直到KitKat,默认情况下才强制执行此操作.

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

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

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.

现在如何?

选项1:使用setImageViewBitmap.

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

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 = 1048576字节= 262144像素= 512 x 512图像

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

当然,您可以使用RGB_565将其压缩得更多,以获得2倍的像素.

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

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

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:

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.

选项2:使用内容提供商

如果由于某种原因您仍然不喜欢IPC限制,则可以随时构建自定义内容提供程序.将那个uri传递到setImageViewUri中,您应该会很好.

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.

路径切换如何?

路径切换不是真正的问题.看来这是一个问题,但是仿真实际上可以正常工作.尝试在//storage/emulated/0/sdcard/mydir/bgs内部创建一个文件,该文件会创建得很好.

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/bgs and the file will create just fine.

您会注意到,尽管该异常是FileNotFoundException,但消息是权限被拒绝".

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