Как получить url файла android studio

Обновлено: 07.07.2024

Перевод документации [1], в которой рассказывается о том, как использовать ресурсы в приложении Android в контексте получения к ним доступа. Все незнакомые сокращения и термины ищите в Словарике [5].

[Как получить доступ к ресурсам]

Как только предоставили ресурс в приложении (эта тема рассмотрена в [2]), Вы можете применить его, ссылаясь на ресурс по его идентификатору ресурса (resource ID). Все идентификаторы resource ID определены в Вашем классе R проекта, который автоматически генерирует утилита aapt.

Когда приложение компилируется, aapt генерирует класс R, который содержит идентификаторы resource ID для всех ресурсов, размещенных в директории res/. Для каждого типа ресурса здесь имеется подкласс R (например подкласс R.drawable предназначен для доступа ко всем рисуемым ресурсам), и для каждого типа ресурса поставлено в соответствие статическое целое число (например, R.drawable.icon). Это целое число и является resource, которые Вы можете использовать для получения доступа к ресурсу и его использования в программе.

Несмотря на то, что класс R то место, где указаны идентификаторы resource ID, Вам никогда не нужно заглядывать в него, чтобы определить resource ID для нужного ресурса. Все, что надо знать - это только символическое имя ресурса. Это имя для resource ID всегда составляется из следующих частей:

• Тип ресурса (resource type): каждый ресурс группируется с другими по своему типу, такому как string (строка), drawable (рисуемый ресурс) и layout (разметка интерфейса). Для получения дополнительной информации по типам ресурсов см. [3].

• Имя ресурса (resource name), которое может быть либо именем файла без расширения, либо значением XML-атрибута android:name attribute (если ресурс относится к простому значению, такому как строка или цвет).

Есть два способа получения доступа к ресурсу:

• В коде Java: используя статическое целое число из субкласса Вашего класса R, например так:

Здесь string является типом ресурса (resource type), и hello является именем ресурса (resource name). Имеется много функций Android API, которые могут получить доступ к ресурсам, когда Вы предоставите им в качестве аргумента resource ID в таком формате (см. далее раздел "Получение доступа к ресурсу в коде Java").

• В XML: используя специальный синтаксис XML, который также соответствует resource ID, заданному в Вашем классе R, например так:

Здесь string также является resource type, и hello также является resource name. Вы можете использовать этот синтаксис в любом месте XML, где это значение ожидается (см. далее раздел "Получение доступа к ресурсу из XML").

[Получение доступа к ресурсу в коде Java]

Вы можете использовать ресурс в коде путем передачи resource ID методу (функции) как параметр. Например, Вы можете установить ImageView для использования ресурса картинки res/drawable/myimage.jpg, используя setImageResource():

Вы также можете запросить отдельные ресурсы с использованием методов в классе Resources, экземпляр которого можно получить вызовом getResources().

Вот общий синтаксис для ссылки на ресурс в коде:

[< package_name >.]R.< resource_type >.< resource_name >

• < package_name > является именем пакета, в котором находится ресурс (эту часть указывать не требуется, если нужен доступ к ресурсам собственного пакета приложения).
• < resource_type > R subclass для типа ресурса.
• < resource_name > это либо имя файла ресурса без расширения, либо android:name значения атрибута в элементе XML (для простых значений ресурсов типа строк и цвета).

См. [3] для дополнительной информации по каждому типу ресурса, и как ссылаться на него.

Есть много методов, которые принимают resource ID как параметр, и Вы можете запросить ресурсы с использованием методов из класса Resources . Вы можете получить экземпляр этого класса вызовом Context.getResources() . Вот некоторые примеры получения доступа к ресурсам из кода:

Предупреждение: не пытайтесь никогда вручную модифицировать файл модуля R.java, поскольку он генерируется автоматически утилитой aapt, когда Ваш проект компилируется. Так что любые сделанные вручную правки в этом файле будут безвозвратно потеряны при следующей компиляции.

[Получение доступа к ресурсу из XML]

Вы можете задавать значения для некоторых атрибутов и элементов XML, используя ссылку на существующий ресурс. Вы часто будете делать это при создании файлов разметки интерфейса (layout file), чтобы предоставить строки и картинки для Ваших виджетов в программе.

Например, если Вы добавите кнопку Button в разметку интерфейса (layout), Вы должны использовать строковый ресурс для текста кнопки:

Примечание: можно конечно вместо ссылки вбить текст напрямую, но это будет плохой практикой, потому что усложнит локализацию приложения на разные языки [2].

Общий синтаксис для ссылки на ресурс в XML:

@[< package_name >:]< resource_type >/< resource_name >

• < package_name > является именем пакета, в котором находится ресурс (эту часть указывать не требуется, если нужен доступ к ресурсам собственного пакета приложения).
• < resource_type > R subclass для типа ресурса.
• < resource_name > это либо имя файла ресурса без расширения, либо android:name значения атрибута в элементе XML (для простых значений ресурсов типа строк и цвета).

См. [3] для дополнительной информации по каждому типу ресурса, и как ссылаться на него.

В некоторых случаях нужно использовать ресурс в качестве значения в файле XML (например, чтобы применить картинку drawable к виджету), то Вы также можете использовать ресурс в XML в любом месте, которое подразумевает применение простого значения. Например, если у Вас есть следующий файл ресурса, который подключает ресурс цвета и строковый ресурс:

Вы можете использовать эти ресурсы в следующем файле разметки интерфейса (layout file) для установки строки текста и его цвета:

В этом случае не нужно указывать имя пакета в ссылке на ресурс, потому что ресурс находится в том же пакете, что и само приложение. Чтобы обратиться к ресурсу системы, Вам нужно добавить в ссылку также и имя пакета, где находится ресурс, например:

Примечание: Вы всегда должны использовать ресурсы для строк, потому что это позволит легко локализовать приложение на другие языки - с помощью создания альтернативных строковых ресурсов, которые будут автоматически подгружаться в зависимости от текущих языковых установок системы. Для информации о том, как создавать альтернативные ресурсы (в том числе и строки локализации), см. [2] (раздел "Предоставление альтернативных ресурсов"). Для полного руководства по локализации Вашего приложения см. Localization.

Вы можете даже использовать ресурсы в XML, чтобы создать псевдонимы (aliases, алиасы). Несмотря на то, что создание алиасов на первый взгляд кажется избыточным, на самом деле это весьма полезно. Это нужно для того, чтобы не плодить одинаковые копии файлов, упростить поддержку проекта и экономить место в памяти (растровые картинки могут занимать много места). Например, Вы можете создать drawable-ресурс, который будет алиасом другого drawable-ресурса:

Читайте больше про создание алиасов в [2], раздел "Создание псевдонимов ресурсов (resource alias)".

[Получения доступа к атрибутам стиля (style attribute)]

Ресурс атрибутов стиля позволяет Вам обращаться к значению атрибута в текущей примененной теме оформления интерфейса. Обращение к атрибуту стиля позволит Вам подстроить внешний вид элементов интерфейса пользователя (UI), чтобы они соответствовали стандартным вариациям оформления, которые действуют в текущей теме - вместо того, чтобы применять жестко закодированное значение. Ссылка на атрибут стиля по существу говорит: "используйте стиль, который определен этим атрибутом в текущей теме".

Чтобы сослаться на атрибут стиля, синтаксис имен почти идентичен нормальному формату ресурса, но вместо at-символа (@) используется знак вопроса (?), и указывать тип ресурса необязательно:

?[< package_name >:][< resource_type >/]< resource_name >

Например, здесь показано, как Вы можете сослаться на атрибут для установки цвета текста, чтобы он соответствовал "главному" цвету текста системной темы:

Здесь атрибут android:textColor задает имя атрибута стиля в текущей теме. Android теперь использует значение, которое применено к атрибуту стиля android:textColorSecondary в качестве величины для виджета редактирования текста android:textColor. Поскольку инструмент системного ресурса знает, что в этом контексте ожидается атрибут ресурса, Вам не нужно явно указывать тип (который может быть ?android:attr/textColorSecondary), и Вы можете исключить тип attr.

[Доступ к ресурсам платформы (Platform Resources)]

Android содержит некоторое количество стандартных ресурсов, таких как стили, темы, и разметки интерфейса (layouts). Чтобы получить доступ к этим ресурсам, указывайте в квалификаторе ссылки на ресурс имя пакета "android". Например, Android предоставляет layout-ресурс, который Вы можете использовать для элементов списка в ListAdapter:

В этом примере simple_list_item_1 является layout-ресурсом, заданным платформой для всех элементов в ListView. Вы может использовать его вместо создания собственного layout для элементов списка. Для дополнительной информации см. руководство разработчика List View.

[Получение доступа к оригинальным файлам]

В редком случае Вам может понадобиться доступ к Вашим оригинальным файлам и директориям. Если это так, то сохранение Ваших файлов в папку res/ работать не будет, потому что единственным способом читать ресурсы из res/ является чтение через resource ID. Вместо этого для доступа к оригинальным файлам ресурсов Вам нужно сохранить их в директорию assets/.

Файлы, сохраненные в директории assets/, не получают resource ID, так что Вы не можете обратиться к ним через класс R или из ресурсов XML. Вместо этого Вы можете запросить файлы из директории assets/ почти так же, как это делается в обычной файловой системе, и читать данные файлов с использованием класса AssetManager .

Однако если Вам нужна возможность читать сырые данные raw (такие как файлы видео или аудио), то сохраните файл в директорию res/raw/, и читайте поток байт с использованием openRawResource() .

Всем привет и это уже третья статья и видео, посвященные работе в Android Studio с json файлами.

Из этой статьи вы узнаете как в android studio получать данные из JSON в ListView с сервера на хостинге.

Мы всё ближе и ближе подходим к тому, чтобы наконец-то начать получать данные с сервера на хостинге, а вот сейчас мы займемся как раз разбором данного примера.

Мы загрузим наш тестовый json файл с пользователями на хостинг и будем получать данные уже непосредственно из интернета.

Надеюсь видео вам понравится, можете пока создается новый проект поставить пальцы вверх, подписаться на канал, и мы приступаем.

Смотрите видео: Android Studio: получение JSON в ListView с сервера на хостинге. Урок № 3

Создаем новый проект, выбираем emptyActivity , традиционно жмем Next, назовём новый проект Load json from url -01 , финиш.

Пока подготавливается проект, хочу сказать, что я выложил наш тестовый json файл на хостинг и буду использовать его в качестве примера. Вы можете выложить свой файл, как Вам будет удобно с вашим содержимым. Замечу, что заходить по ftp на сервер, создавать домены, поддомены, создавать директории на хостинге вы обязаны уметь.

Давайте поработаем над нашим проектом, кое-что будем использовать из второго урока, код будет немного совпадать, кто не смотрел предыдущие примеры, обязательно посмотрите.

Давайте сразу через New Resource File снова сделаем row.xml , для вывода пунктов нашего списка, чуть позже вернемся к нему.

Откроем AndroidManifest.xml , в нем нужно будет указать разрешение для работы с интернетом.

Также нам понадобится gradle файл, и в него мы вставим имплементацию библиотеки, которую Вы наверное, уже знаете, может кто-то уже слышал, это volley, по крайней мере так я её произношу.

Синхронизируем gradle , произошло добавление, будем работать с этой библиотекой, она как раз используется для сетевых запросов, для получения данных с сайтов и тому подобного.

В AndroidManifest добавим пользовательское разрешение для работы с интернетом.

Это вроде как позволяет работать с недостоверными, скажем так с точки зрения Google, сайтами это требование корпорации добра, для вашей безопасности. С манифестом и с gradle закончили.

Слой listview

Теперь перейдем в activity_main , по традиции мы снова будем делать listview , заменим на RelativeLayout , textview меняем на listview , убираем отсюда опять всё ненужное.

Так значит для listview добавим android:id listView , ширина и высота - wrap_content .

Добавим еще один элемент для отображения сетевой активности, ProgressBar ширина wrap_content , высота тоже wrap_content .

Сделаем видимость ProgressBar в

Вот теперь важное: для ProgressBar добавить нужно центрирование по горизонтали и по вертикали, чтобы элемент был по центру экрана.

Так он пока где-то находится, его не видно, можно посмотреть. он находится по центру и будет крутиться.

Перейдём в row.xml для вывода пунктов, сделаем здесь LinearLayout , ширина match_parent , а высота wrap_content , ориентация вертикальная, отступы – 16dp .

Слой row

Так теперь добавим два textview , вы уже знаете какие, это у нас будут для name и email.

Добавим для видимости текст,

размер текста сделаем равным 20sp . Можно было не писать, можно было скопировать с предыдущего примерно, но напишу. То же самое и для поля email .

Так значит нам нужно будет создать новый класс для обработки. Наш класс мы назовём ListViewAdapter .

И теперь я буду вставлять куски кода, потому как мы его писали в прошлый раз, но для тех, кто не смотрел, кое-что расскажу, буду уже всё равно блоками вставать, поскольку он практически готов.

Снова напишем конструктор, в котором будем вызываться контекст, слой, которые у нас row , будем вызывать поля, в принципе можно там первое вызвать name и уже будет работать и список который будет передавать данные.

Метод super это всё вызывает, здесь присвоение переменных.

Ну и опять без изменений практически из второго видео, с некоторыми оговорками получается вот такая функция.

В getView определяем слой для вывода данных, обращаемся к элементам пункта name , email . В блоке обработки исключений try/catch циклично присваиваем текст, получая его из списка userlist .

Кто смотрел мое второе видео по json , тот знает, что это такое, в принципе больше на этом останавливаться не будем.

Теперь переходим в mainactivity и поработаем в ней. Итак, нам нужно будет объявить несколько переменных, переменная JSON_URL в которой мы будем хранить наш адрес, по которому будет лежать наш файл на сайте.

и ListView listView для списка.

Я надеюсь вы знаете как заливать файлы на хостинг, поэтому я не буду рассказывать, как мне удалось создать папку api в поддомене и положить туда файл, думаю это вам уже известно, если вы занимаетесь и обучайтесь разработке Android приложений для себя, либо по учёбе, по работе.

Сразу же мы получаем наш listView , наш список через findViewById

А вот теперь мы напишем вот такую строчку,

это по сути в onCreate больше ничего не будет. Дальше будет несколько функций, которые мы напишем в рукопашную.

И эта функция loadJSONFromURL будет вызывать наш адрес, и будем получать данные.

Далее напишем ручками Private void loadJSONFromURL , в качестве параметра Stirling передаём url .

Нужно будет обратиться к нашему элементу ProgressBar , который у нас указан в activity_main progressBar

ProgressBar надо будет сделать видимым

Теперь пишем StringRequest , обратите внимание это мы работаем с библиотекой volley ,

передаём наш url , пишем new Response.Listener

Открываем скобки пишем @Override ,

Нам нужно добавить метод onResponse , подключить сюда onResponse .

Далее делаем ProgressBar не видимым.

Всё мы его скрыли, теперь у нас идёт обработчик исключений try , пишем

и указываем нашу таблицу users , которая у нас внутри файла users.json .

Объявляем ArrayList JSONObject

и вот здесь мы напишем ту функцию, которую мы писали в прошлый раз.

В прошлый раз, я хочу напомнить, мы её вставим вне функций, мы её Встаём целиком и полностью, можете скопировать её из второго примера. Поскольку будем выполнять то же самое действие здесь.

Не буду останавливаться, но тут происходит наполнение данными из массива. Передаём jsonArray , далее пишем ListAdapter adapter

И теперь для списка установим адаптер

Блок исключений catch

Далее идет Response.ErrorListener

В нем Toast выводит ошибки. Что такое тосты уже знаете, последние две строчки данной функции

Вот теперь только вызываться наша библиотека, которая в конце концов вызовет наконец-то запрос и сформирует нужный результат.

Так, здесь я пропустил запятую после переменной url , и в принципе больше у нас ни каких нюансов быть не должно… А они будут…)

Сохраняем, запускаем… Эмулятор запустился, и мы получили данные…

Ошибка в кодировке при получении данных с JSON

Поскольку наш файл вряд ли был в кодировке UTF-8 , но здесь должен быть четко UTF-8 . Напишу для себя UTF-8 , должна быть такая кодировка, тогда у нас будут русские буквы, русский текст нормально выглядить.

Сложно догадаться, что это Коля, Вася, Федя, и тому подобное, хотя email отобразился нормально.

Значит нам нужно будет написать ещё одну небольшую функция, которая превратит наш ответ – response , превратит эту кашу в кодировку UTF-8 .

Итак давайте исправим это недоразумение, написав еще одну функцию EncodingToUTF8

В качестве параметра передаём string response , сразу try обработчик, пишем массив байт, code

Ответ в строку, получим байты в кодировке ISO-8859-1 , западноевропейская кодировка, и конвертируем в UTF-8 , перегоним нашу абракадабру в понятный вид.

После обработки ошибок Catch вернем строковое значение response.

Вот такая получилась небольшая функция в принципе когда мы перейдём наконец-то в четвёртый урок, в четвёртом занятие, мы будем получать данные уже непосредственно из PHP с базы данных на хостинге, и этот костыль не понадобится, поскольку мы обойдемся без неё, там уже будем конвертировать текст, можно в базе указать.

И давайте её вызовем EncodingToUTF8 наш response , сохраним и перезапустим.

Вот так, всего лишь одна небольшая функция и мы превратили абракадабру во вполне понятной вид.


Поскольку становится всё более очевидным, что схема file прекращает своё существование, давайте рассмотрим, как всё это будет работать сейчас.

Посмотрим на такую ситуацию со стороны потребителя: вам передают Uri с каким-нибудь контентом в случае, когда раньше вы ожидали путь к файлу. Как вы будете получать этот контент?

Во-первых, убедитесь, что в любом месте, где у вас есть <intent-filter> для схемы file, у вас также есть <intent-filter> для content, с областью видимости для соответствующего MIME типа. Вы можете получить контент Uri другими способами (например, в onActivityResult()), но если вы поддерживаете файл-подобный контент для таких действий, как ACTION_VIEW, убедитесь, что вы поддерживаете как file, так и content Uri.

Затем, если Uri имеет схему content, вы можете сделать следующее с экземпляром ContentResolver:

  • Вызовите openInputStream() для чтения контента.
  • Вызовите getType(), чтобы получить тип MIME данных.
  • Вызовите query(), запрашивающий OpenableColumns, в котором вы сможете получить размер контента и некоторую разновидность отображаемого имени, связанного с контентом.

И это, в общем-то, всё.

К сожалению, хотя и не всем нравится эти решение, но многие думают, что это единственный подходящий вариант.

Просто забрать путь

Некоторые разработчики вызывают getPath() у Uri, а затем пытаются открыть его как файл (например, new File(uri.getPath())).

Не делайте так!

Этот способ никогда не был надёжным, так как он предполагает схему file и то, что у вас есть прямой доступ к местоположению файла с заданным путём.

Если у Uri есть какая-либо другая схема, например content, путь в значительной мере становится бесполезным для вас.

Попытка выбрать какие-либо отдельные части из Uri и работать с ними вряд ли окажется успешной для вас.

Представить, что MediaStore знает, чего вы хотите

Некоторые разработчики пытаются запросить MediaStore для столбца DATA в надежде, что они смогут конвертировать Uri в путь к файлу.

Не делайте так!

Не каждый content Uri поступает из MediaStore. На самом деле, в настоящее время относительно немногие Uri так делают. MediaStore ничего не знает о значениях Uri от других поставщиков. Кроме того, даже если вы получите MediaStore Uri, который может индексировать медиа на съёмном носителе, у вас не будет доступа к файловой системе.

Попробовать извлечь путь

Некоторые разработчики используют более сложный вариант для вышеупомянутых подходов, с двумя тоннами кода, чтобы посмотреть на полномочия Uri и попытаться получить путь, основанный на эвристике, разработанной для разных полномочий.

Не делайте так!

Тот факт, что это возможно, является частичной ошибкой Google, поскольку они не сделали значения Uri более скрытыми.

Однако, этот способ тоже ненадёжен:

  • Приложения могут менять свои структуры Uri, и поэтому эвристика, которая работает сегодня, может не работать завтра.
  • Возможно, у вас не будет доступа к файлу, даже если вы определите путь.
  • Скоро случится Кембрийский взрыв приложений, публикующих собственный контент, используя своих собственных поставщиков и значения Uri, благодаря запрету на схему file. Вам необходимо поддерживать этих поставщиков, поэтому вам необходимо использовать метод openInputStream() в любом случае.

Ниже представлен список вопрос, которые могут возникнуть в данной ситуации.

Как получить имя файла?

Вы не можете этого сделать.

Вы можете посмотреть последний сегмент Uri. Это может быть имя файла, а может и не быть. Нет требования, чтобы content Uri использовал реальное имя файла в качестве последнего сегмента пути.

Кроме того, в зависимости от того, откуда контент идёт, фактически никакого файла может не существовать. Предположим. что кто-то в заметку с длинной записью в приложении для заметок, и это приложение делает её доступной через Uri для доступа к другим приложениям. Пользователь не создавал файл, не загружал, не делал ничего, связанного с файлами, с этой заметкой. Даже если для неё есть подлинное имя файла, оно не будет иметь никакого значения для пользователя.

Хорошо, тогда как мне получить расширение файла?

Вы не можете этого сделать.

Ещё раз, вы можете узнать, заканчивается ли Uri тем, что выглядит как имя файла. Нет никакого гарантии, что что-то вроде foo.bar будет являться файлом с расширением .bar.

Вы можете использовать MimeTypeMap или аналогичные виды преобразователей, чтобы попытаться получить MIME тип, который вы получаете из getType(), и затем получить расширение файла. Однако эти конвертеры обрабатывают только популярные MIME типы и не могут обработать кастомные.

Что делать, если мне нужно передать файл в библиотеку?

Во-первых, проверьте библиотеку на наличие в ней варианта InputStream с методом для файла, который вы хотите использовать. Если он есть, используйте InputStream.

Затем, рассмотрите замену библиотеку на ту, которая имеет вариант InputStream.

Наконец, создайте локальную копию контента, получив InputStream из ContentResolver, подучив FileOutputStream в локальном файле (например, внутри getCacheDir() для внутреннего хранилища) и используя операции ввода-вывода для копирования из InputStream в OutputStream. flush(), getFD.sync() и close() FileOutputStream, и теперь у вас есть файл. который вы можете передать в библиотеку.

Конечно, это копия контента, поэтому она может стать устаревшей. Этот способ хорош для одноразовой операции и подходит для случаев, когда вам законным образом нужна локальная копия файла.

Как долго я могу использовать Uri?

Предполагая, что на стороне провайдера ничего не происходит, Uri должен быть действителен в течение всего процесса, но после этого он может стать недействительным.

Представьте, что Uri является глубокой ссылкой на какой-нибудь контент, требующий аутентификации. URL, который вы получаете, является рабочим, поскольку пользователь прошёл аутентификацию. URL может быть полезен даже некоторое время, пока сеанс активен. Но в итоге сеанс завершится и URL станет бесполезным.

Но что делать, если мне понадобится контент на более длительное время?

Вы можете вызвать takePersistableUriPermission() в ContentResolver. Если провайдер предлагает удержать разрешения, и вы их принимаете, то система запомнит, что у вас есть доступ к Uri. Соблюдайте осторожность, вы можете использовать метод для неограниченного доступа к контенту бескончно или до тех пор, пока пользователь не переместит, удалит или сделает недоступным к контенту по старому Uri.

Проблема в том, что takePersistableUriPermission() не говорит вам, были ли получены разрешения. Вы должен будете вызвать getPersistedUriPermissions() и посмотреть, есть ли у вас разрешения. Возможно, здесь нет разрешений, которые можно удержать.

Зачем столько боли?

  • файлов, в том числе тех, к которым другие люди не имеют доступа.
  • столбцов BLOB в базе данных.
  • зашифрованных материалов, которые дешифруются на лету.
  • материалов, которые хранятся в сети и должны быть загружены и сохранены в кеш.
  • материалов, которые генерируются на лету.

Использование значений content Uri намного более гибкое и предлагает больше различных параметров безопасности.

Мы знаем, что Intent имеет атрибут action. С помощью этого атрибута обычно дается указание действия. Например, просмотр или редактирование. Но действие обычно совершается не просто так, а с чем-либо. Значит кроме указания действия, мы должны указывать на объект, с которым эти действия нужно произвести. Для этого Intent имеет атрибут data.

Один из способов присвоения значения этому атрибуту – метод setData (Uri data) у объекта Intent. На вход этому методу подается объект Uri.

Uri – это объект, который берет строку, разбирает ее на составляющие и хранит в себе эту информацию. Строка, конечно, должна быть не любая, а составлена в соответствии с этим документом RFC 2396. Uri имеет кучу методов, которые позволяют извлекать из распарсенной строки отдельные элементы.

Смотрим, чего нам возвращают методы:

Понятия Scheme, Authority, Host, Path и пр. – взяты из RFC дока, ссылку на который я дал выше. Там можно найти их полное описание, понять что они означают и свериться с тем, что нам вернул Uri.

Рассмотрим еще примеры:

(Код, написанный выше, идет одной строкой на самом деле. Здесь идут пробелы вокруг @ из-за особенностей разметки)

uri.getScheme(): geo
uri.getSchemeSpecificPart(): 55.754283,37.62002

Здесь уже получилось выделить только Scheme и SchemeSpecificPart.

Аналогично, получилось выделить только две части из строки.

Контакт из адресной книги

uri.getScheme(): content
uri.getSchemeSpecificPart(): //contacts/people/1
uri.getAuthority(): contacts
uri.getPath(): /people/1
uri.getLastPathSegment(): 1

В этом примере Scheme равен content. Это особый тип данных – Content Provider. Он позволяет любой программе давать доступ к своим данным, а другим программам – читать и менять эти данные. Эту тему мы рассмотрим позднее, и сами будем создавать такой тип данных.

Здесь можно посмотреть какие стандартные Uri поддерживаются.

Чтобы посмотреть координаты на карте, необходимо приложение Google Maps. Его нет в стандартных образах Android систем (тех, что вы в SDK Manager скачивали). Нужен образ, название которого начинается с "Google APIs"

Создайте AVD на платформе Google APIs с API Level 10. Назовите его на ваше усмотрение.


Создадим проект. Обратите внимание, используем платформу Google APIs версии 2.3.3


Project name: P0311_SimpleIntents
Build Target: Google APIs 2.3.3
Application name: SimpleIntents
Package name: ru.startandroid.develop.p0311simpleintents
Create Activity: MainActivity

Если у вас не получилось установить Google APIs, то создавайте проект как обычно - с платформой Android 2.3.3. Просто не будет работать вызов Google Maps в этом примере.

Сформируем экран main.xml

На экране три кнопки. Первая будет открывать веб-страницу, вторая - карту, третья – звонилку.

Пишем код в MainActivity.java:

Я использовал три разных способа создания Intent-а и задания его атрибутов.

В случае btnMap использовался конструктор Intent(). Он просто создает Intent. А в следующих строках мы уже присваиваем ему атрибуты action и data. action – снова ACTION_VIEW, а в качестве data мы создаем Uri из пары координат - 55.754283,37.62002. Этот Intent означает, что мы хотим посмотреть на карте указанные координаты.

В случае btnCall используем конструктор Intent (String action). На вход ему сразу подается action, а data указывается позже. action в данном случае – ACTION_DIAL – открывает звонилку и набирает номер, указанный в data, но не начинает звонок. В data – помещаем Uri, созданный из номера телефона 12345.

Три этих способа приводят к одному результату - Intent с заполненными атрибутами action и data. Какой из них использовать - решать вам в зависимости от ситуации.

Т.к. нашему приложению понадобится интернет, чтобы открыть ссылку и посмотреть карту, надо чтобы на вашем компе интернет был.

Также в файле манифеста приложения, на вкладке Permission добавьте элемент Uses Permission и справа в поле Name выберите android.permission.INTERNET. Это даст приложению доступ в интернет. Правда у меня почему-то и без этого все работает … Пока не понял почему.

Все сохраняем и запускаем приложение


Жмем кнопку Web,

открывается стандартный браузер и отображает содержимое страницы по ссылке


Возвращаемся, жмем Map. Отображается карта, которая показывает место, соответствующее указанным координатам.


Возвращаемся, жмем Call. Отображается стандартный экран набора номера и видим, что номер, который мы указывали в data, уже набран. Нам остается только нажать кнопку звонка.


Скорее всего, сейчас есть много вопросов типа «Что будет если … ». На некоторые из них сразу могу ответить и предлагаю вам поэкспериментировать в текущем приложении:

1) Что будет, если указать координаты без приставки geo:

Система ругнется, что не нашла подходящего Activity (см. логи). Т.к. в Activity карты настроен Intent Filter, который (как я думаю) настроен на data c Schema = geo.

Аналогично не сработает звонилка, если указать номер без приставки tel.

2) Что будет, если в координатах оставить geo, но координаты указать кривые?

Если мы попробуем посмотреть, например, такие координаты geo:a,b, то карта запустится, но скажет нам Unable to load the URL. Т.е. данные подошли по Schema, но оказались некорректными.

3) Что будет, если координаты указать верно, но action использовать не ACTION_VIEW, а ACTION_EDIT.

Получается, что мы хотим отредактировать место на карте заданное этими координатами. Но система говорит нам, что она не нашла такое Activity. Потому что приложение Google Maps ожидает Intent с action = ACTION_VIEW и оно сможет показать нам это место на карте. А на редактирование оно не подписывалось )

Необходимо понять, что все приложения в системе заточены под конкретные действия с конкретными типами данных. И если вы попробуете позвонить на адрес сайта, или открыть на карте номер телефона – то система просто не найдет приложения, способные на это.

На следующем уроке:

- пишем простой браузер

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

- новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Читайте также: