Android-невозможно открыть содержимое: файл: / / / хранение / эмуляция / 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 (с последней launcher 4.4 эта ошибка не существует). У меня также есть некоторые RemoteViews в моем приложении и все работы правильно.
Я также добавил в манифест либо READ_EXTERNAL_STORAGE, либо WRITE_EXTERNAL_STORAGE.
как я могу решить?
UPDATE: я проверяю метод 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.
4 ответов
появляется 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, чтобы получить 2x пикселей.
также обратите внимание, что вам может не понадобиться огромное изображение, если ваш виджет мал. Ваш 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);
просто имейте в виду, что возвращаемые значения находятся в dip не пиксели, поэтому вам нужно будет преобразовать их для масштабирования растрового изображения.
Вариант 2: используйте контент-провайдера
если по какой-то причине вам все еще не нравится ограничение IPC, вы всегда можете создать пользовательский контент-провайдер. Передайте этот uri в setImageViewUri, и вам будет хорошо идти.
как насчет переключателя пути?
переключатель пути не является реальной проблемой. Похоже, что это проблема, но эмуляция на самом деле работает отлично. Попробуйте создать файл внутри //storage/emulated/0/sdcard/mydir/bgs
и файл будет создан просто отлично.
вы заметите, что в то время как исключение является FileNotFoundException сообщение отказано в разрешении.
начиная с Lollipop, Google представила новый способ явно дать приложениям разрешение, которое вы хотите использовать на своем устройстве, и отключить те, которые вы хотите запретить приложение. Если вы заметили, в вашем Android monitor, журнал показывает
java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)
EACCESS permission denied
является причиной печально известного java FileNotFoundException
.
чтобы решить эту проблему, просто получить разрешение приложения и включить хранение для вашего приложения
Я думаю, что вы вводите путь SD-карты вручную. Вместо ручного ввода пути SD-карты вы должны получить путь хранения, как это:
File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";