- Создание удобного OpenFileDialog для Android
- Android file open dialog
- About
- Осуществление выбора файлов в Android и копирование выбранного файла в другое место
- EDIT (текущий код)
- редактировать с помощью кода работа благодаря @Ю. С., @Lukas Knuth и @CommonsWare.
- 5 ответов
- Диалоговые окна
- Общая информация
- Класс Dialog
- Методы onCreateDialog() и onPrepareDialog()
- Диалоговое окно AlertDialog
- AlertDialog с ссылкой
Создание удобного OpenFileDialog для Android
Наверное, как и многие разработчики под Android, столкнулся на днях с необходимостью реализовать в своем приложении выбор файла пользователем. Так как изначально в Android такого функционала нет, обратился к великому и ужасному. Это показалось мне странным, но из вороха вопросов на stackoverflow и небольшого числа отечественных форумов можно выделить всего три основных источника:
- Android File Dialog – почти все ссылки из stackoverflow ведут сюда. В принципе, неплохое решение, но реализовано через отдельную activity, а хотелось чего-то в духе OpenFileDialog’а из .Net.
- В данной статье речь идет вообще об отдельном файл-менеджере, и почерпнуть какие-то идеи из неё не удалось.
- Идея же отсюда очень понравилась, однако, как мне показалось реализовать все это можно несколько красивее.
В результате, начав реализовывать своё решение, я столкнулся с некоторыми трудностями решать которые показалось очень интересно. А посему, решил описать в данной статье не просто готовое решение, а все шаги, которые к нему привели. Желающие пройти их вместе –
Итак, приступим! В любой привычной среде (я использую IntelliJ IDEA) создадим новое приложение. На главной activity расположим одну единственную кнопку и напишем к ней, пока пустой, обработчик нажатия:
Создадим новый класс с конструктором:
а в обработчике кнопки вызовем диалог:
Кнопки показались, теперь надо бы и сами файлы найти. Начнем поиск с корня sdcard, для чего определим поле:
и реализуем следующий метод:
(так как главное требование к классу – работать сразу у любого разработчика, без подключения дополнительных библиотек, — то никаких google-collections использовать не будем, и с массивами приходится работать по старинке), а в конструкторе к вызову setNegativeButton добавим .setItems(getFiles(currentPath), null).
Что же, неплохо, однако файлы не отсортированы. Реализуем для этого дела Adapter как внутренний класс, заменим setItems на setAdapter и немного перепишем getFiles:
Еще лучше, но нам надо по клику на папке идти внутрь. Можно достучаться до встроенного listview, но я просто подменил его собственным (это потом пригодится). Плюс, изменения adapter’а внутри обработчика listview вызывало exception, и список файлов пришлось вынести в отдельное поле:
Отлично, вот только нажав на папку Android мы получаем список всего из одного каталога data, и наше окно тут же уменьшается в размере.
Возможно это нормально, но мне это не понравилось, и я стал искать возможности размер сохранить. Единственный найденный мною вариант – это установка setMinimumHeight. Установка этого свойства для listview вызвала дополнительные проблемы, но они решились оберткой его в LinearLayout:
Результат, все равно получился немного не таким, каким хотелось бы: при старте диалог развернут на весь экран, а после перехода в каталог Android – уменьшается до 750px. Да еще и экраны разных устройств имеют разную высоту. Решим сразу обе этих проблемы, установив setMinimumHeight в максимально возможную для текущего экрана:
Не нужно пугаться того, что мы устанавливаем в setMinimumHeight полный размер экрана, сама система уменьшит значение до максимально допустимого.
Теперь появляется проблема понимания пользователя, в каком каталоге он сейчас находится, и возврата вверх. Давайте разберемся с первой. Вроде все легко — установить значение title в currentPath и менять его при изменении последнего. Добавим в конструктор и в метод RebuildFiles вызов setTitle(currentPath).
А нет – заголовок не изменился. Почему не срабатывает setTitle после показа диалога, документация молчит. Однако мы может это исправить, создав свой заголовок и подменив им стандартный:
И снова не все ладно: если пройти достаточно далеко, то строка в заголовок влезать не будет
Решение с установкой setMaximumWidth не верно, так как пользователь будет видеть только начало длинного пути. Не знаю, насколько верно мое решение, но я сделал так:
Решим теперь проблему с возвратом. Это достаточно легко, учитывая, что у нас есть LinearLayout. Добавим в него еще один TextView и немного отрефракторим код:
Возможность возвращаться на шаг вверх, может привести пользователя в каталоги, к которым ему доступ запрещен, поэтому изменим функцию RebuildFiles:
(cообщение пока не очень информативное, но вскоре мы добавим разработчику возможность исправить это).
Ни один OpenFileDialog не обходится без фильтра. Добавим и его:
Обратите внимание — фильтр принимает регулярное выражение. Казалось бы – все хорошо, но первая выборка файлов сработает в конструкторе, до присвоения фильтра. Перенесем её в переопределенный метод show:
Осталось совсем чуть-чуть: вернуть выбранный файл. Опять же, я так и не понял зачем нужно устанавливать CHOICE_MODE_SINGLE, а потом все равно писать лишний код для подсветки выбранного элемента, когда он (код) и так будет работать без CHOICE_MODE_SINGLE, а потому обойдемся без него:
Источник
Android file open dialog
Show a dialog in your android app that allows the user to select a file or folder from his phones memory or SD card.
###1. Gradle dependency (JCenter) Add the following to your build.gradle:
###2. Maven dependency (JCenter) Add the following to your pom.xml:
###Don’t forget Your app needs the according permissions to acces the phones memory or an sd card. See [Using External Storage] (http://developer.android.com/guide/topics/data/data-storage.html#filesExternal) and Requesting Permissions at Runtime or the implementation in the example app (line 63ff).
Copyright (c) 2016 Sebastian Dombrowski
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the «Software»), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED «AS IS», WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
About
Show a dialog in your android app that allows the user to select a file or folder from his phones memory or SD card.
Источник
Осуществление выбора файлов в Android и копирование выбранного файла в другое место
я пытаюсь реализовать средство выбора файлов в своем проекте Android. Что я смог сделать до сих пор-это :
а затем в onActivityResult()
это открытие выбора файла, но это не то, что я хочу. Например, я хочу выбрать файл (.txt), а затем сделать что File и затем использовать его. С этим кодом я думал, что получу полный путь но этого не происходит; например я: /document/5318/ . Но с этим путем я не могу получить . файл. Я создал метод под названием PathToFile() что возвращает File :
что я пытаюсь сделать, это позволить пользователю выбрать File из любого места означает DropBox , Drive , SDCard , Mega , etc. И я не нахожу способ сделать это правильно, я попытался получить Path затем получить File этой Path . но это не работает, поэтому я думаю, что лучше получить , а потом с этим File программно я Copy этот и Delete .
EDIT (текущий код)
там у меня есть вопрос, потому что я не знаю, что поддерживается как text/plain , но я собираюсь расследовать это, но на данный момент это не имеет значения.
на onActivityResult() я использовал то же самое, что @Lukas Knuth ответ, но я не знаю, смогу ли с ним Copy этой File в другую часть моего SDcard я waitting для его ответ.
редактировать с помощью кода работа благодаря @Ю. С., @Lukas Knuth и @CommonsWare.
это Intent где я принимаю только файлы text/plain .
на onActivityResult() создать URI где я получаю данные Intent я создаю File где я сохранить абсолютный путь делаешь content_describer.getPath(); , а затем я сохраняю имя пути, чтобы использовать его в TextView С content_describer.getLastPathSegment(); (это было потрясающе @Y. S. Не знал об этой функции), и я создаю второй File который я назвал destination и я пошлю AbsolutePath чтобы создать этот File .
также я создал функцию, которую вы должны отправить source file и destination file что мы создали ранее, чтобы скопировать в новую папку.
также я создал функцию, которая говорит Мне, существует ли эта папка или нет (я должен отправить destination file , если он не существует, я создаю эту папку, и если это произойдет не я ничего не делаю.
еще раз спасибо за вашу помощь, надеюсь, вам понравится этот код, сделанный со всеми вами, ребята:)
5 ответов
Шаг 1-Используйте неявное Intent :
выбрать файл из устройства, вы должны использовать неявный Intent
Шаг 2 — получить абсолютный путь к файлу:
чтобы получить путь к файлу из Uri , сначала попробуйте использовать
здесь data — это Intent вернулся в onActivityResult() .
если это не работает, используйте следующий метод:
At хотя бы один из этих двух методов должен дать вам правильный, полный путь.
Шаг 3-скопируйте файл:
что вы хотите, я считаю, это скопировать файл из одного места в другое.
для этого абсолютно необходимо иметь абсолютный путь к файлу как источника и места назначения.
во-первых, получить абсолютный путь к файлу, используя либо getPath() способ или uri.getPath() :
затем создайте два File объекты следующим образом:
здесь CustomFolder — каталог на внешнем диске, куда вы хотите скопировать файл.
затем используйте следующий метод для копирования файла из одного места в другое:
попробуйте это. Это должно сработать.
Примечание: Vis-a-vis Lukas’ ответ — то, что он сделал, это использовать метод под названием openInputStream() возвращает контент of a Uri , ли Uri представляет файл или URL-адрес.
еще один перспективный подход — FileProvider :
есть еще один способ, с помощью которого можно получить файл из другого приложения. Если приложение делится своими файлами через FileProvider , тогда можно достать FileDescriptor объект, который содержит конкретную информацию об этом файл.
для этого используйте следующее Intent :
и в onActivityResult() :
здесь mInputPFD это ParcelFileDescriptor .
ссылки:
Я сделал то же самое, чтобы позволить пользователю выбрать изображение из папки :
1) есть кнопка Открыть:
2) Функция открыть папку изображений:
3) результат деятельности, где я получаю путь к файлу изображения и делаю все, что хочу с путем изображения:
4) и теперь самая важная часть, класс W_ImgFilePathUtil, код не от меня, но он позволяет вам получить полный путь любого выбранного файла, будь то на sd-карте, Google drive.
открытый класс W_ImgFilePathUtil <
заключение: код работает с путем изображения, но уверен, работает с любым типом файла.
надеюсь, что это поможет решить вашу проблему.
As @CommonsWare уже отмечалось, Android возвращает вам Uri , что является более абстрактным понятием, чем путь к файлу.
он также может описать простой путь к файлу, но он также может описать ресурс, к которому обращаются через приложения (например, content://media/external/audio/media/710 ).
если вы хотите, чтобы ваш пользователь выбрал любой файл с телефона, чтобы прочитать его из вашего приложения, вы можете сделать это, попросив файл (как вы сделали правильно) , а затем использовать ContentResolver для получения InputStream на Uri это возвращается сборщиком.
важно: некоторые поставщики (например, Dropbox) хранят/кэшируют свои данные на внешнем хранилище. Вам нужно будет иметь android.permission.READ_EXTERNAL_STORAGE -разрешение объявлено в вашем манифесте, иначе вы получите FileNotFoundException , хотя файл есть.
обновление: Да, вы можете скопировать файл, прочитав его из одного потока и пишу другому:
удаление файла, вероятно, невозможно, так как файл не принадлежат для вас он принадлежит приложению, которое поделилось им с вашим. Таким образом, приложение-владелец отвечает за удаление файла.
A Uri не является файлом. А Uri ближе к URL веб-сервера. Это непрозрачный адрес, который имеет значение только для » сервера «(или в этом случае ContentProvider ).
так же, как вы используете InputStream для чтения в байтах, представленных веб-URL, вы используете InputStream для чтения в байтах, представленных Uri . Вы получаете такой поток, позвонив openInputStream() на ContentResolver .
передайте URI, возвращенный в onActivityResult в этом методе
Источник
Диалоговые окна
Начиная с Android 3.0, работа с диалоговыми окнами чуть изменилась. С тех пор статья не переписывалась и могла морально устареть.
Общая информация
В некоторых случаях требуется показать диалоговое окно, где пользователю нужно сделать какой-нибудь выбор или показать сообщение об ошибке. Безусловно, можно создать собственное окно, расположить в нем нужные кнопки и обрабатывать их нажатия. Но, в Android уже есть собственные встроенные диалоговые окна, которые гибко настраиваются под задачи. Использование диалоговых окон для простых задач позволяет сократить число классов Activity в приложении, экономя ресурсы памяти. Ведь вам не придётся регистрировать активность в манифесте, думать над компоновкой элементов на экране и так далее.
Диалоговые окна в Android представляют собой полупрозрачные «плавающие» активности, частично перекрывающие родительский экран, из которого их вызвали. Как правило, они затеняют родительскую активность позади себя с помощью фильтров размывания или затемнения. Вы можете установить заголовок с помощью метода setTitle() и содержимое с помощью метода setContentView().
Android поддерживает следующие типы диалоговых окон:
- Dialog — базовый класс для всех типов диалоговых окон;
- AlertDialog — диалоговое окно с кнопками, списком, флажками или переключателями;
- CharacterPickerDialog — диалоговое окно, позволяющее выбрать символ с ударением, связанный с базовым символом;
- ProgressDiaiog — диалоговое окно с индикатором прогресса при помощи компонента ProgressBar. В API 26 признан устаревшим.
- DatePickerDialog — диалоговое окно выбора даты с элементом DatePicker
- TimePickerDialog — диалоговое окно выбора времени с элементом TimePicker
Если ни один из существующих типов диалоговых окон вам не подходит, то можете создать своё собственное диалоговое окно.
Класс Dialog
Класс Dialog является базовым для всех классов диалоговых окон. Поскольку ProgressDialog, TimePickerDialog И DatePickerDialog — расширение класса AlertDialog, они также могут иметь командные кнопки.
Каждое диалоговое окно должно быть определено внутри активности или фрагмента, в которых будет использоваться. Диалоговое окно можно открыть один раз или несколько раз.
Для отображения диалогового окна необходимо вызвать метод showDialog() и передать ему в качестве параметра идентификатор диалога (константа, которую надо объявить в коде программы), который вы хотите отобразить.
Метод dismissDialog() прячет диалоговое окно (но не удаляет), не отображая его на экране. Окно остаётся в пуле диалоговых окон данной активности. При повторном отображении при помощи метода showDialog() будет использована кэшированная версия окна.
Метод removeDialog() удаляет диалоговое окно из пула окон данной активности. При повторном вызове метода showDialog() диалоговое окно придётся создавать снова.
Рассмотрим базовый пример создания диалогового окна на основе класса Dialog. Создайте простейшую разметку для диалогового окна — текстовое поле внутри LinearLayout. В разметку главной активности добавьте кнопку для вызова диалогового окна. В коде для главной активности напишем:
По умолчанию при показе диалогового окна главная активность затемняется. В документации есть константы, позволяющие управлять степенью затемнения:
На эмуляторе я не заметил разницы. В старой версии Android 2.3 был ещё эффект размытия WindowManager.LayoutParams.FLAG_BLUR_BEHIND, который теперь считается устаревшим. Если вы по упрямству всё равно пропишите данный эффект, то получите не эффект размытия, а чёрный фон. Кто знает, может вас устроит данный вариант.
Методы onCreateDialog() и onPrepareDialog()
Метод onCreateDialog() вызывается один раз при создании окна. После начального создания при каждом вызове метода showDialog() будет срабатывать обработчик onPrepareDialog(). Переопределив этот метод, вы можете изменять диалоговое окно при каждом его выводе на экран. Это позволит привнести контекст в любое из отображаемых значений. Если требуется перед каждым вызовом диалогового окна изменять его свойства (например, текстовое сообщение или количество кнопок), то можно реализовать внутри этого метода. В этот метод передают идентификатор диалога и сам объект Dialog, который был создан в методе onCreateDialog().
Так как в одном приложении может быть несколько диалоговых окон, то необходимо заранее определить диалоговое окно, которое будет использоваться в активности. Для этого создаётся идентификатор (константа с целым числом). При вызове метода showDialog() вы передаёте данный идентификатор диалогового окна в качестве параметра. После этого идёт вызов метода onCreateDialog(), который возвращает экземпляр нужного диалогового окна.
Можно создавать диалог без onCreateDialog(), например в обработчике нажатия кнопки вызова диалога, но тогда он не будет присоединён к текущей активности. Чтобы прикрепить его к активности, необходимо вызвать метод setOwnerActivity(), передав ему в качестве параметра текущую активность.
Перейдём к примеру. Если в активности должны вызываться несколько различных диалоговых окон, сначала необходимо определить целочисленный идентификатор для каждого диалога, например:
Эти идентификаторы потом можно использовать в вызове метода showDialog() и в обработчике события onCreateDialog() в операторе switch:
Следует отметить, что методы Activity.onCreateDialog() и Activity.onPrepareDialog() устарели. Используйте DialogFragment.
Диалоговое окно AlertDialog
Примеры создания диалоговых окон типа AlertDialog рассмотрены в этой статье
AlertDialog с ссылкой
Практического смысла возможно не имеет, но можно сделать текст сообщения ссылкой.
Источник