Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Разработка мобильных приложений в среде Android Studio. Учебное пособие
.pdf
5.1. Загрузка данных с сайта
71
e.printStackTrace();
}
Чтобы загрузить данные, находящиеся по переданной ссылке, необходимо использовать класс HttpURLConnection [33]. Данный класс предназначен для установки связи с ресурсом, поддержания соединения, а также
загрузки данных. Начало соединения обеспечивается методом openConnection(), который открывает сессию (также помещается в блок обработки
ошибок):
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
Далее необходимо проверить, есть ли доступ к запрашиваемому ресурсу. Для этого используется код ответа на запрос (200 = запрос прошел
удачно):
try {
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK)
{
}
} catch (IOException e) {
e.printStackTrace();
}
После этого можно непосредственно получать данные с использованием InputStreamReader – потока для приема [34]. Его необходимо инициализировать потоком класса HttpURLConnection, который можно получить
путем использования метода getInputStream. Общая задача заключается в
том, чтобы прочитать текстовые данные, поэтому для получения данных из

5. Работа с сетью
72
потока InputStreamReader используется метод класса BufferedReader readLine(), который вернет всю прочитанную строку. Класс BufferedReader поз-
воляет накапливать полученные данные и отдавать их порциями по запросу, в данном случае построчно [35]. Данный класс будет иметь размер буфера, указанного при создании, в примере 8128. Таким образом, чтение
данных по запросу на сайт будет реализовано в следующем виде:
StringBuilder response = new StringBuilder();
BufferedReader input = new BufferedReader(new InputStreamReader
(conn.getInputStream()), 8192);
String line = null;
while ((line = input.readLine()) != null)
{
response.append(line);
}
input.close();
В примере используется класс StringBuilder, позволяющий выполнять
операции со строками, в данном случае, добавление строк друг к другу (метод append) [36]. Его использование необязательно.
5.2. JSON-файлы
В настоящее время для передачи какой-либо информации по сети
Интернет используется формат JSON, предназначенный для кодирования
объектов JavaScript в виде строк. Структура JSON может включать в себя:
1. Объекты (непосредственно данные, например строка или число)
следующего формата:
{ name : value , .... }
2. Массивы – обозначаются в квадратных скобках:
[ object , object .... ]
3. Значения – перечисление строк или чисел через запятую.

5.2. JSON-файлы
73
5.2.1. Чтение JSON-файлов
В Android имеется встроенное средство для чтения JSON [37] – набор
классов для каждой части структуры:
1) для объектов – JSONObject;
2) массивы – JSONArray;
3) значения – JSONStringer;
4) ошибки – JSONExeption.
У каждого из представленных выше классов есть методы для получения внутренней структуры – массива, объекта или значения: getBoolean,
getDouble, getJSONObject и т.д. Стоит отметить, что эти классы не содержат функциональных возможностей для автоматической конвертации
JSON в объект класса. Задача последовательного применения методов для
правильного «парсинга» структуры, как и преобразование полученных значений к объекту класса, полностью лежит на разработчике.
Рассмотрим процесс разбора структуры файла на примере. Предположим, чтоимеется следующий JSON:
{
"fruits":[
"Apple",
"Avocado",
"Banana",
"Cherry"
]
}
В данной структуре только один объект – весь JSON. Он содержит
еще один объект – массив значений. Каждый элемент представленного
массива – строка, которая уже не является объектом JSON-структуры, а
просто значением.
Для того чтобы получить из этой структуры значения (в данном случае названия фруктов), необходимо выполнить следующие действия:
1. Скачанный json с сайта представляет из себя строку, поэтому первый шаг – это преобразование строки в формат JSONObject. Для этого
необходимо создать экземпляр класса JSONObject с конструктором, принимающим на вход строку:

5. Работа с сетью
74
String json = "{\n" +
"\"fruits\":[\n" +
"\t\"Apple\",\n" +
"\t\"Avocado\",\n" +
"\t\"Banana\",\n" +
"\t\"Cherry\"\n" +
"\t]\n" +
"}\n";
JSONObject object = new JSONObject(json);
2. Далее из созданного объекта необходимо получить следующий
элемент – массив, создав экземпляр класса JSONArray, который инициализируется с помощью содержащегося в object массива. Данный массив можно получить с использованием функции getJSONArray(). В одном объекте
может содержаться несколько массивов, других объектов и просто значений, каждое из которых должно имеет свое название. В примере название
массива – fruits, значение которого из объекта получаем следующим образом:
JSONArray fruitsArray = object.getJSONArray("fruits");
Например, для получения числа из объекта необходимо воспользо-
ваться следующей функцией:
int myInt = object.getInt("myIntName");
Аналогично имеется возможность получить почти все типы данных.
3. Получение элемента массива осуществляется с использованием
метода getString() (getInt, getLong и др.). Входным значением для данных
функций является индекс массива:
String fruitName = fruitsArray.getString(4);
5.2.2. Использование GSON
При достаточно простой JSON-структуре рассмотренный метод «пар-
синга» является приемлемым. Но в случае, если структура содержит много

5.2. JSON-файлы
75
объектов разных типов данных, то рекомендуется использовать библиотеку
Gson [38]. Она позволяет преобразовать JSON-структуру в соответствующий ей java-класс и наоборот. Данная библиотека не входит в стандартный
набор средств среды разработки, поэтому в начале ее нужно подключить в
gradle, в части dependencies:
implementation 'com.google.code.gson:gson:2.8.5'
После чего необходимо «пересобрать» проект для закачивания необ-
ходимых файлов.
Далее создадим класс, представляющий JSON-структуру, в java-коде.
Это можно сделать либо вручную, либо используя специальные онлайнресурсы (например, сайт http://www.jsonschema2pojo.org)[39]. Рассмотренная ранее структура массива фруктов имеет достаточно простой формат,
поэтому создадим класс вручную с произвольным названием, например
Fruits:
public class Fruits {
}
Рассматриваемая структура содержит массив строк, поэтому его
необходимо включить в класс. В данном случае вместо типа данных массива рекомендуется использовать List<String>, начальное значение которого
null:
public class Fruits {
private List<String> fruits = null;
}
Далее необходимо указать, что созданный список соответствует массиву с названием fruits из рассматриваемого JSON. В этом случае используется аннотация SerializedName(“name”), которая отвечает за хранение
имени объекта при его сериализации и десериализации:
public class Fruits {
@SerializedName("fruits")
private List<String> fruits = null;
}

5. Работа с сетью
76
Аннотации представляют из себя дескрипторы, включаемые в текст
программы, и используются для хранения метаданных программного кода,
необходимых на разных этапах жизненного цикла программы. Информация, хранимая в аннотациях, может использоваться соответствующими обработчиками для создания необходимых вспомогательных файлов или для
маркировки классов, полей и т.д.
Рассматриваемая библиотека преобразует JSON в java-класс с использованием сериализации, поэтому необходимо указать списку еще одну
аннотацию – @Expose, определяющую можно ли данное поле получить из
JSON-структуры, т.е. можно ли его сериализовать:
public class Fruits {
@SerializedName("fruits")
@Expose
private List<String> fruits = null;
}
Создание класса, отображающего структуру JSON, закончено.
Теперь можно использовать библиотеку GSON. Для начала необходимо создать экземпляр класса Gson:
Gson gson = new Gson();
Данный класс содержит метод fromJson(), принимающий два параметра. Один из которых может быть одним из следующих типов:
1. String.
2. Reader.
3. JsonReader.
4. JsonElement.
Каждый из представленных выше типов содержит JSON-структуру в
том или ином виде. В данном учебном пособии будет использоваться ее
строковое представление. Таким образом, преобразование JSON в класс
Fruits будет представлено в следующем виде:
Gson gson = new Gson();
Fruits fruitItems = gson.fromJson(json, Fruits.class);

5.3. Геолокация
77
где в классе Fruits в списке fruits содержится массив фруктов из JSON-
структуры.
И не забываем, что вся работа с сетью выполняется в дополнительном
потоке, реализация которого представлена в разд. 4.
5.3. Геолокация
Часто в приложении необходимо определять местонахождение пользователя (геолокацию). Рассмотрим действия, которые необходимо выполнить для реализации геолокации.
Первое – определить в приложении разрешения на использование геолокации и сети Интернета, добавив в манифест следующие строки:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission
android:name="android.permission.INTERNET"/>
Второе – подключить библиотеки сервисов GooglePlay, содержащие
требуемый инструментарий для работы с геоданными [40], дописав в gradle
следующую строку:
implementation 'com.google.android.gms:play-services-location:16.0.0'
Далее вся работа будет происходить в классе Activity. Сначала проверяем, дал ли пользователь разрешения на использование его местоположения [41]. Данная проверка должна происходить в начале работы Activity,
таким образом, помещаем ее в функцию onCreate(). Если текущая
версия > 23, то запрос выполняет подтверждение разрешения:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
Если в манифесте нет разрешения на использование геолокации, то необходимо добавить его в манифест:

5. Работа с сетью
78
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new
String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1000);
} else {
LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
try {
String country = getLocation(location.getLatitude(), location.getLongitude());
Log.d("My_country",country);
} catch (Exception e) {
e.printStackTrace();
}
}
Функция ActivityCompat.checkSelfPermission() принимает два
параметра – текущее Activity и проверяемое разрешение
Manifest.permission.ACCESS_COARSE_LOCATION. Выходное значение
типа int: 0 – разрешение дано. Вместо числового значения можно
использовать константную системную переменную
PackageManager.PERMISSION_GRANTED. Если разрешение дано, происходит вызов функции getLocation(), содержимое и описание которой приведено ниже. Если же нет, то необходимо проверить, запрашивалось ли
раньше это разрешение, и отклонил ли его пользователь функцией
ActivityCompat.shouldShowRequestPermissionRationale(). Если не отклонил,
показываем окно запроса разрешения функцией
ActivityCompat.requestPermissions() (рис. 24), которая на вход принимает
текущее Activity и перечень необходимых для запроса разрешений. Последний параметр задается, чтобы знать, на какие разрешения происходит
запрос (может быть любое число по решению разработчика).
Для того чтобы после нажатия одной из кнопок получить результат
выполнения операции, необходимо определить функцию
onRequestPermissionsResult().

5.3. Геолокация
79
Рис. 24. Запрос разрешения на геолокацию
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1000: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);

5. Работа с сетью
80
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Location location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
String country = getLocation(location.getLatitude(), location.getLongitude());
Log.d("My_country",country);
return;
}
} else {
Toast.makeText(this, "Permission not granted",
Toast.LENGTH_SHORT).show();
}
break;
}
}
}
В массиве grantResults хранится информация о разрешенных действиях. Можно просто проверить этот массив на пустоту, и если он не пуст, то
разрешения были даны. Можно также проверить параметр requestCode
(третий параметр в списке параметров функции
ActivityCompat.requestPermissions()), который указывает, на какие разрешения был запрос.
При помощи разрешения
Manifest.permission.ACCESS_FINE_LOCATION) приложение может
получить доступ к точному местоположению.
Manifest.permission.ACCESS_COARSE_LOCATION – приблизительное
местоположение.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
