Урок 16. Знакомство с форматом JSON. Парсинг JsonObject на примере объекта User
JSON формат
В этом уроке мы с вами более подробно познакомимся с форматом JSON. А потом из этого формата получим наш User объект.
JSON стал общепринятын форматом для обмена данными в клиент-серверных приложения. Он является универсальным форматом для обмена данными.
Представьте, что вам нужно создать систему приложений, в которую входит, сервер, web-клиент, ios-клиент, android-клиент. У всех технологий разные языки, разные особенности. Поэтому сервер отвечает в формате JSON, а клиенты на своей стороне приводят к нужному формату ответы. Подробнее про JSON формат можно почитать здесь, но на данном этапе ваших знаний уже вполне хватит.
JSONObject, работа с JSON в java коде
Давайте создадим новый класс в пакете network и назовём его JsonParser для преобразования Json-строк в необходимые нам объекты. Добавим в него один метод, который назовём getUser(String response):
JsonParser.java
1
2
3
4
5
6
7
8
9
10
package colibri.dev.com.colibritweet.network;importcolibri.dev.com.colibritweet.pojo.User;publicclassJsonParser{public User getUser(String response){returnnull;}}
Мы будем использовать этот метод внутри класса HttpClient, передавая в него ответ от сервера в формате String, возвращая объект User. Давайте разберём преобразование, рассмотрим структура хранения JSON. В том уроке мы в конце вывели ответ от сервера в log и увидели очень большой объект JSON. На данном этапе нам необходимы только те поля, которые мы отображаем на экране. Поэтому опустим остальные поля и оставим только те, которые нам нужны:
Видим, что наш JSON полностью повторяет структуру нашего объекта User. Теперь можно приступить к парсингу (преобразованию) данных.
Первое, что надо сделать – это создать JSON объект из строки.
JsonParser.java
1
2
3
4
5
6
7
8
9
10
11
package colibri.dev.com.colibritweet.network;importcolibri.dev.com.colibritweet.pojo.User;publicclassJsonParser{public User getUser(String response){
JSONObject userJson =new JSONObject(response);returnnull;}}
Видим, что AndroidStudio подчёркивает эту строку, указывая что надо обработать исключение или добавить его к сигнатуре метода. Можем нажать alt + enter и увидеть два этих варианта решения проблемы. Добавим исключение к сигнатуре, чтобы обработать исключения в клиентском коде. Для этого выберем вариант Add exception to method signature.
JSONObject представляет из себя структуру типа HashMap (ключ – значение). Т.е. чтобы получить значения поля id нам необходимо выполнить вызов метода userJson.getLong("id"). Давайте сделаем тоже самое для каждого поля. После этого метод будет выглядеть так:
JsonParser.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publicclassJsonParser{public User getUser(String response)throws JSONException {
JSONObject userJson =new JSONObject(response);long id = userJson.getLong("id");
String name = userJson.getString("name");
String nick = userJson.getString("screen_name");
String location = userJson.getString("location");
String description = userJson.getString("description");
String imageUrl = userJson.getString("profile_image_url");int followersCount = userJson.getInt("followers_count");int followingCount = userJson.getInt("favourites_count");returnnull;}}
Т.е. вот так по названию поля мы можем достать его значение. Нам попался самый простой случай, где наши значения являются примитивными типами. На практике мы поработаем с массивами элементов, вложенными объектами.
Давайте создадим объект User, передав ему в конструктор все поля, которые мы только что достали из userJson.
publicclassHttpClient{privatestaticfinal String HEADER_AUTHORIZATION ="Authorization";privatestaticfinal String GET ="GET";privatefinal JsonParser jsonParser;publicHttpClient(){
jsonParser =new JsonParser();}public User readUserInfo(long userId)throws IOException, JSONException {
String requestUrl ="https://api.twitter.com/1.1/users/show.json?user_id="+ userId;
URL url =new URL(requestUrl);
HttpURLConnection connection =(HttpURLConnection) url.openConnection();// add auth header to request
String authHeader = getAuthHeader(requestUrl);
connection.setRequestProperty(HEADER_AUTHORIZATION, authHeader);
connection.connect();
InputStream in;int status = connection.getResponseCode();if(status != HttpURLConnection.HTTP_OK){
in = connection.getErrorStream();}else{
in = connection.getInputStream();}
String response = convertStreamToString(in);
User user = jsonParser.getUser(response);return user;}// остальной код ниже не изменился}
Добавили JsonParser как final поле в классе HttpClient и инициализируем его в конструкторе.
После этого добавили строку User user = jsonParser.getUser(response); в конец метода getUserInfo и поменяли возвращаемый тип на User и добавили новое исключение JSONException в сигнатуру метода. Отлично, теперь изменим код в UserInfoActivity и запустим приложение.
в UserInfoActivity нам нужно изменить метод loadUserInfo. Выглядеть он будет так:
publicclassUserInfoActivityextends AppCompatActivity {// остальной код выше не изменился
@SuppressLint("StaticFieldLeak")privatevoidloadUserInfo(final Long userId){new AsyncTask<Void, Void, User>(){
@Override
protected User doInBackground(Void... voids){try{return httpClient.readUserInfo(userId);}catch(IOException | JSONException e){
e.printStackTrace();returnnull;}}
@Override
protectedvoidonPostExecute(User user){
displayUserInfo(user);}}.execute();}// остальной код ниже не изменился}
Мы изменили:
Возвращаемый тип Asynctask со String на User.
Добавили в catch блок перехват исключения типа IOException | JSONException.
В onPostExecute мы заменили вызов Log.d() на вызов реального метода отображения displayUserInfo(user).
Давайте запустим наше приложение.
Всё работает! Только видим, что наш ник выводится без символа @. Давайте изменим метод getNick() в классе User. Будем добавлять в него символ @ самостоятельно, т.к. сервер это не сделал.
User.java
1
2
3
4
5
6
7
publicclassUser{// Остальной код выше не изменилсяpublic String getNick(){return"@"+ nick;}// Остальной код ниже не изменился}
Запустим наше приложение и увидим, что теперь с форматом поля nick всё в порядке:
Сайт использует cookie-файлы для того, чтобы вам было удобнее им пользоваться. Для
продолжения работы с сайтом, вам необходимо принять использование cookie-файлов.
JSON формат
В этом уроке мы с вами более подробно познакомимся с форматом
JSON
. А потом из этого формата получим нашUser
объект.JSON
стал общепринятын форматом для обмена данными в клиент-серверных приложения. Он является универсальным форматом для обмена данными.Представьте, что вам нужно создать систему приложений, в которую входит, сервер,
web
-клиент,ios
-клиент,android
-клиент. У всех технологий разные языки, разные особенности. Поэтому сервер отвечает в форматеJSON
, а клиенты на своей стороне приводят к нужному формату ответы. Подробнее проJSON
формат можно почитать здесь, но на данном этапе ваших знаний уже вполне хватит.JSONObject, работа с JSON в java коде
Давайте создадим новый класс в пакете
network
и назовём егоJsonParser
для преобразованияJson
-строк в необходимые нам объекты. Добавим в него один метод, который назовёмgetUser(String response)
:JsonParser.java
Мы будем использовать этот метод внутри класса
HttpClient
, передавая в него ответ от сервера в форматеString
, возвращая объектUser
. Давайте разберём преобразование, рассмотрим структура храненияJSON
. В том уроке мы в конце вывели ответ от сервера вlog
и увидели очень большой объектJSON
. На данном этапе нам необходимы только те поля, которые мы отображаем на экране. Поэтому опустим остальные поля и оставим только те, которые нам нужны:Видим, что наш
JSON
полностью повторяет структуру нашего объектаUser
. Теперь можно приступить к парсингу (преобразованию) данных.Первое, что надо сделать – это создать
JSON
объект из строки.JsonParser.java
Видим, что
AndroidStudio
подчёркивает эту строку, указывая что надо обработать исключение или добавить его к сигнатуре метода. Можем нажатьalt + enter
и увидеть два этих варианта решения проблемы. Добавим исключение к сигнатуре, чтобы обработать исключения в клиентском коде. Для этого выберем вариантAdd exception to method signature
.JSONObject
представляет из себя структуру типаHashMap
(ключ – значение). Т.е. чтобы получить значения поляid
нам необходимо выполнить вызов методаuserJson.getLong("id")
. Давайте сделаем тоже самое для каждого поля. После этого метод будет выглядеть так:JsonParser.java
Т.е. вот так по названию поля мы можем достать его значение. Нам попался самый простой случай, где наши значения являются примитивными типами. На практике мы поработаем с массивами элементов, вложенными объектами.
Давайте создадим объект
User
, передав ему в конструктор все поля, которые мы только что достали изuserJson
.JsonParser.java
Вот и всё! Теперь давайте добавим использование нашего класса внутри класса
HttpClient
.HttpClient.java
Добавили
JsonParser
какfinal
поле в классеHttpClient
и инициализируем его в конструкторе.После этого добавили строку
User user = jsonParser.getUser(response);
в конец методаgetUserInfo
и поменяли возвращаемый тип наUser
и добавили новое исключениеJSONException
в сигнатуру метода. Отлично, теперь изменим код вUserInfoActivity
и запустим приложение.в
UserInfoActivity
нам нужно изменить методloadUserInfo
. Выглядеть он будет так:UserInfoActivity.java
Мы изменили:
Asynctask
соString
наUser
.catch
блок перехват исключения типаIOException | JSONException
.onPostExecute
мы заменили вызовLog.d()
на вызов реального метода отображенияdisplayUserInfo(user)
.Давайте запустим наше приложение.
Всё работает! Только видим, что наш ник выводится без символа
@
. Давайте изменим методgetNick()
в классеUser
. Будем добавлять в него символ@
самостоятельно, т.к. сервер это не сделал.User.java
Запустим наше приложение и увидим, что теперь с форматом поля
nick
всё в порядке:Полный листинг кода:
HttpClient.java
JsonParser.java
UserInfoActivity.java
Поздравляем, вы только что закончили полный цикл работы с сервером. Давайте подведём итоги:
JSON
широко используется для обмена данными между клиентом и серверомключ - значение
, что позволяет удобно работать с нимAndroid
есть классJSONObject
, который позволяет парситьJSON
в любой необходимый формат данных