До KitKat (или до новой галереи) Intent.ACTION_GET_CONTENT
возвращаемый URI, как этот
Содержание: // СМИ / внешние / изображения / СМИ / 3951.
Использование ContentResolver
и запрашивая
MediaStore.Images.Media.DATA
вернул URL файла.
Однако в KitKat Галерея возвращает URI (через «Last») следующим образом:
Содержание: //com.android.providers.media.documents/document/image: 3951
Как мне справиться с этим?
android
android-intent
android-gallery
android-contentresolver
Майкл Грайфенедер
источник
источник
Uri
должно быть открыто как поток черезContentResolver
. Я давно нервничаю по поводу приложений, которые предполагают, что acontent://
Uri
, представляющий файл, всегда может быть преобразован в aFile
.InputStream
вContentResolver
заранее определенное место, чтобы у него было известное имя файла. Тем не менее, это звучит расточительно для меня. Любые другие предложения?InputStream
чем JNI? К сожалению, вариантов для вас не так много.InputStream
вместо файла (что здорово). Только чтение тега EXIF немного сложно и требует библиотеки Drew Noakes . Большое спасибо за ваши комментарии.Ответы:
Попробуй это:
Наверное нужно
для
источник
Это не требует специальных разрешений и работает с Storage Access Framework, а также с неофициальным
ContentProvider
шаблоном (путь к файлу в_data
поле).Смотрите актуальную версию этого метода здесь .
источник
Authority: com.google.android.apps.docs.storage
иSegments: [document, acc=1;doc=667]
. Я не уверен, но предположим, чтоdoc
значение - этоUri
идентификатор, к которому вы можете обратиться. Скорее всего, вам потребуется настроить разрешения, как описано в разделе «Авторизация приложения на Android» здесь: developers.google.com/drive/integrate-android-ui . Пожалуйста, обновите здесь, если вы выясните это._data
будет работать, если ContentProvider не поддерживает его. Рекомендуется следовать инструкциям @CommonsWare и больше не использовать полный путь к файлу, поскольку это может быть файл в облаке Dropbox вместо реального файла.Была та же проблема, пробовал решение выше, но хотя оно работало в целом, по какой-то причине я получал отказ в разрешении на контент-провайдера Uri для некоторых изображений, хотя у меня было
android.permission.MANAGE_DOCUMENTS
правильно добавлено разрешение.В любом случае нашел другое решение - принудительно открывать галерею изображений вместо просмотра документов KITKAT:
и затем загрузите изображение:
РЕДАКТИРОВАТЬ
ACTION_OPEN_DOCUMENT
может потребоваться сохранение флагов разрешений и т. д., что обычно приводит к исключениям безопасности ...Другое решение состоит в том, чтобы использовать
ACTION_GET_CONTENT
комбинацию,c.getContentResolver().openInputStream(selectedImageURI)
которая будет работать как на pre-KK, так и на KK. Kitkat будет использовать просмотр новых документов, и это решение будет работать со всеми приложениями, такими как Фото, Галерея, Обозреватель файлов, Dropbox, Google Drive и т. Д.), Но помните, что при использовании этого решения вы должны создать изображениеonActivityResult()
и сохранить его на SD-карта, например. Воссоздание этого изображения из сохраненного URI при следующем запуске приложения приведет к возникновению исключения безопасности в средстве распознавания контента, даже если вы добавите флаги разрешений, как описано в документации по API Google (именно это и произошло, когда я провел некоторое тестирование)Кроме того, в Руководстве по API для разработчиков Android предлагается следующее:
источник
Intent.ACTION_GET_CONTENT
. В любом случае я сохранилIntent.createChooser()
оболочку новогоIntent
, чтобы пользователь мог выбрать приложение для просмотра, и работал как положено. Может кто-то видит недостатки этого решения?Как уже упоминалось в Commonsware, вы не должны предполагать, что поток, который вы получаете,
ContentResolver
конвертируется в файл.Что вы действительно должны сделать, это открыть
InputStream
изContentProvider
, а затем создать растровое изображение из него. И это работает на 4.4 и более ранних версиях, не нужно размышлять.Конечно, если вы обрабатываете большие изображения, вы должны загрузить их с соответствующими
inSampleSize
: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . Но это другая тема.источник
Я считаю, что уже опубликованные ответы должны направить людей в правильном направлении. Однако вот что я сделал, это имело смысл для устаревшего кода, который я обновлял. Унаследованный код использовал URI из галереи, чтобы изменить, а затем сохранить изображения.
До версии 4.4 (и google drive) URI выглядели так: content: // media / external / images / media / 41
Как указано в вопросе, они чаще всего выглядят так: content: //com.android.providers.media.documents/document/image: 3951
Поскольку мне нужна была возможность сохранять изображения, а не нарушать уже существующий код, я просто скопировал URI из галереи в папку данных приложения. Затем был создан новый URI из файла сохраненного изображения в папке данных.
Вот идея:
Примечание. CopyAndClose () просто выполняет файловый ввод-вывод для копирования InputStream в FileOutputStream. Код не опубликован.
источник
Просто хотел сказать, что этот ответ блестящий, и я давно его использую без проблем. Но некоторое время назад я натолкнулся на проблему, заключающуюся в том, что DownloadsProvider возвращает URI в формате
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf
и, следовательно, происходит сбой приложения,NumberFormatException
поскольку невозможно анализировать его сегменты URI так долго. Ноraw:
сегмент содержит прямой URI, который может быть использован для получения ссылочного файла. Итак, я исправил это, заменивisDownloadsDocument(uri)
if
содержимое следующим:источник
Я объединил несколько ответов в одно рабочее решение, которое приводит к пути к файлу
Тип MIME не имеет значения для примера.
Результат обработки
FilePickUtils
источник
Вопрос
Как получить фактический путь к файлу из URI
Ответ
Насколько мне известно, нам не нужно получать путь к файлу из URI, потому что в большинстве случаев мы можем напрямую использовать URI для выполнения нашей работы (например, 1. получение растрового изображения 2. отправка файла на сервер и т. Д. .)
1. Отправка на сервер
Мы можем напрямую отправить файл на сервер, используя только URI.
Используя URI, мы можем получить InputStream, который мы можем напрямую отправить на сервер, используя MultiPartEntity.
пример
2. Получение BitMap из URI
Если URI указывает на изображение, мы получим растровое изображение, иначе null:
Комментарии
Ссылка
источник
Эта библиотека Android обрабатывает изменения в KitKat (включая более старые версии - 2.1+):
https://github.com/iPaulPro/aFileChooser
Используйте
String path = FileUtils.getPath(context, uri)
для преобразования возвращаемого Uri в строку пути, используемую на всех версиях ОС. Подробнее об этом здесь: https://stackoverflow.com/a/20559175/860488источник
Для тех, кто все еще использует код @Paul Burke с Android SDK версии 23 и выше, если ваш проект встретился с ошибкой, говорящей о том, что вам не хватает EXTERNAL_PERMISSION, и вы очень уверены, что уже добавили разрешение пользователя в свой файл AndroidManifest.xml. Это потому, что вы можете использовать Android API 23 или выше, и Google заставит вас снова гарантировать разрешение, пока вы выполняете действие для доступа к файлу во время выполнения.
Это означает: если ваша версия SDK 23 или выше, вас просят о разрешении ЧИТАТЬ и ЗАПИСАТЬ, когда вы выбираете файл изображения и хотите узнать его URI.
И следующий мой код, в дополнение к решению Пола Бёрка. Я добавляю этот код, и мой проект начинает работать нормально.
И в вашей деятельности и фрагменте, где вы запрашиваете URI:
В моем случае CompatUtils.java - это место, где я определяю метод verifyStoragePermissions (как статический тип, чтобы я мог вызывать его в рамках другого действия).
Кроме того, это имеет больше смысла, если вы сначала создадите условие if, чтобы увидеть, является ли текущая версия SDK выше 23 или нет, прежде чем вызывать метод verifyStoragePermissions.
источник
Этот ответ от m3n0R на вопрос android получить реальный путь по Uri.getPath (), и я не претендую на кредит. Я просто думал, что люди, которые еще не решили эту проблему, могли бы использовать это.
источник
cursor.getString(idx);
Пожалуйста, постарайтесь избегать использования метода takePersistableUriPermission, потому что это вызвало для меня исключение времени выполнения. / ** * Выбрать из галереи. * /
OnActivity для результата для обработки данных изображения:
@ Override protected void onActivityResult (int requestCode, int resultCode, данные намерения) {
источник
Если кому-то интересно, я сделал рабочую версию Kotlin для
ACTION_GET_CONTENT
:источник
Я попробовал несколько ответов здесь, и я думаю, что у меня есть решение, которое будет работать каждый раз, а также управлять разрешениями.
Он основан на умном решении от LEO. Этот пост должен содержать весь код, необходимый для работы, и должен работать на любом телефоне и версии Android;)
Чтобы иметь возможность выбрать файл с SD-карты, вам понадобится это в вашем манифесте:
Константы:
Проверьте разрешение и запуститеImagePick, если это возможно
Ответ разрешения
Управление разрешением ответа
Запуск выбора изображения
Управление ответом выбора изображения
Это все люди; это работает для меня на всех телефонах, которые у меня есть.
источник
Это полный взлом, но вот что я сделал ...
Поэтому, играя с настройкой DocumentsProvider , я заметил, что пример кода (
getDocIdForFile
около строки 450) генерирует уникальный идентификатор для выбранного документа на основе (уникального) пути к файлу относительно указанного корня, который вы ему даете (то есть то, что вы установилиmBaseDir
в строке 96).Таким образом, URI выглядит примерно так:
content://com.example.provider/document/root:path/to/the/file
Как говорят в документах, он предполагает только один корень (в моем случае это,
Environment.getExternalStorageDirectory()
но вы можете использовать где-то еще ... затем он берет путь к файлу, начиная с корня, и делает его уникальным идентификатором, предваряя "root:
". Поэтому я Можно определить путь,"/document/root:
удалив "part из uri.getPath (), создав реальный путь к файлу, выполнив что-то вроде этого:Я знаю. Это позорно, но это сработало. Опять же, это зависит от того, используете ли вы собственный провайдер документов в своем приложении для генерации идентификатора документа.
(Также есть лучший способ построить путь, который не предполагает, что «/» является разделителем пути и т. Д. Но вы поняли идею.)
источник
file://
намерения из внешнего средства выбора файлов, вы также можете проверить полномочия, как в примере выше, чтобы убедиться, что это от вашего собственного провайдера, и если это так, вы можете также используйте путь, чтобы «подделать» новоеfile://
намерение, используя путь, который вы извлекли,StartActivity()
и позвольте вашему приложению забрать его. Я знаю, ужасно.Это работало нормально для меня:
источник
Основываясь на ответе Пола Бёрка, я столкнулся со многими проблемами при разрешении пути URI внешней SD-карты, поскольку большинство предлагаемых «встроенных» функций возвращают пути, которые не разрешаются в файлы.
Тем не менее, это мой подход к его обработке // TODO неосновных томов .
Обратите внимание, что это зависит от иерархии, которая может отличаться для каждого производителя телефона - я не проверял их все (до сих пор это работало хорошо на Xperia Z3 API 23 и Samsung Galaxy A3 API 23).
Пожалуйста, подтвердите, если это не работает хорошо в другом месте.
источник
Ответ @paul burke отлично работает как для изображений с камеры, так и для галереи для API уровня 19 и выше, но не работает, если минимальный SDK вашего проекта Android установлен ниже 19, а некоторые ответы, приведенные выше, не работают как для галереи, так и для галереи. камера. Ну, я изменил код @paul burke, который работает для уровня API ниже 19. Ниже приведен код.
источник
Ответ на ваш вопрос заключается в том, что вам нужно иметь разрешения. Введите следующий код в файле manifest.xml:
У меня это сработало ...
источник