Приложение, которому нечего показывать на экране, становится довольно скучным, верно? Итак, возникает вопрос, откуда мы можем получить интересные факты для отображения в нашем приложении для Android? Из киберпространства, конечно!

Существуют тысячи веб-сайтов, которые предоставляют информацию, которая может пригодиться, чтобы оживить наши приложения через REST или Representational State Transfer, API-интерфейсы, которые определяют способ выполнения веб-сервисов. Многие сайты позволяют нам создать учетную запись для доступа к таким ресурсам, как изображения, данные и API REST. Почти все мобильные и веб-приложения используют JSON для таких задач, как обмен данными с веб-сервером. В этом мы поговорим о том, как работать с JSON в Dart и Flutter.

Dart, являющийся основным языком для любого приложения Flutter, — это то, над чем мы будем работать. Мы подойдем к этому таким образом, чтобы сохранить совместимость с Flutter. В этой статье мы рассмотрим основы анализа JSON в Dart. Так что к концу у вас будет приложение со списком, поля которого будут заполняться данными, полученными из API.

Шаг 1:

Чтобы получить данные JSON, во-первых, мы должны реализовать http-методы, а для того, чтобы использовать http-методы во Flutter, и для этого нам нужно будет импортировать библиотеку, которая позволяет использовать некоторые распространенные http-методы, такие как GET, POST , ПОСТАВИТЬ, УДАЛИТЬ и т.д.

Прежде всего, здесь нужно перейти к файлу wer pubspec.yaml и в разделе зависимостей написать:

http: ^0.12.0+1

Как только вы закончите с этим, сохраните файл, и флаттер самопроизвольно запустит команду «flutter packages get». Этот шаг будет учтен как минимум при работе с Visual Code Studio.

Шаг 2:

Теперь перейдите к файлу wer main.dart. И обязательно удалите все, что есть в файле.

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

После этого внесите ‘ package:flutter/material.dart’; импортируйте ‘package:http/http.dart’ как http. Пакет, который используется первым, важен для компонентов Материала. Второй пакет — это тот, который мы вставляем в зависимости нашего проекта.

Теперь определите точку входа в приложении как:

void main(){runApp(NewApp())}; Or in short, void main() => runApp(NewApp());

Далее определим его как класс NewApp.

Шаг 3:

Что мы сделаем, так это напишем весь наш код в одном классе, и класс будет иметь несколько состояний, поэтому этот класс будет с состоянием.

class NewApp extends StatefulWidget { @override _NewAppState createState() => _NewAppState(); }class _NewAppState extends State<NewApp> { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold() body: Center(), ), ); } }

Шаг 4:

Теперь, после создания базовой структуры, давайте начнем работать над получением результата с помощью API. Для этого мы будем использовать JSONPlaceholder REST API. В частности, https://jsonplaceholder.typicode.com/photos.

Полученный JSON состоит из списка объектов, каждый из которых имеет пять атрибутов: albumId, id, title, url и thumbnailUrl. . Давайте пока сосредоточимся на трех атрибутах. И это:

После этого мы сформируем класс с этими тремя атрибутами вместе с конструктором. Мы также включим фабричный метод fromJson() в класс Photo, чтобы упростить создание объекта Photo из объекта JSON.

class Photo{ int id; String title, thumbnailUrl; Photo({this.id,this.title,this.thumbnailUrl}); factory Photo.fromJson(Map<String, dynamic> json) { return Photo( id: json['id'] as int, title: json['title'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); } }

Шаг 5:

Далее создадим сетевой запрос.

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

У Flutter есть очень замечательная функция, известная как Future. Future — это основной класс Dart для работы с асинхронными операциями. Объект Future представляет собой потенциальное значение или ошибку, которые будут доступны когда-нибудь в будущем. Future всегда сопровождается типом данных (например, Future‹int› или Future‹String› и т. д.).

Мы не можем предсказать, когда наш запрос будет улучшен. Однако мы можем получить наш результат через 1 секунду, 10 секунд или 10 минут, или даже могут быть шансы вообще не получить результат из-за какой-то ошибки, и вместо этого нам, возможно, придется просто смириться с ошибкой. И именно поэтому наша функция вернет не List‹Photo›, а Future‹List‹Photo››.

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

Итак, в основном,

Future<List<Photo>> obtainJson() async{ final response = await http.get('https://jsonplaceholder.typicode.com/photos');//1 String responseBody = response.body;//2 dynamics jsonObject = json.decode(responseBody);//3 final convertedJsonObject = jsonObject.cast<Map<String, dynamic>>();//4 List<Photo> list = convertedJsonObject.map<Photo>((json) => Photo.fromJson(json)).toList();//5 return list;//6 }
  1. В первой строке мы выполнили HTTP-запрос get и пометили его как await, поэтому дальнейшие операции в теле функции не будут выполняться до тех пор, пока не будет возвращена операция get. Операция http get возвращает значение Future‹Response›. Таким образом, мы сохранили это значение в «response».
  2. Далее мы перейдем к основной части этого ответа. Это тело имеет тип String, поэтому мы сохраним его в переменной «responseBody» типа String.
  3. Далее мы преобразуем эту строку в объект JSON. Функция json.decode() примет параметр типа string и восстановит результирующее тело JSON.
  4. Теперь, когда у нас есть объект JSON, мы перенесем его в Map типа String, dynamic, т.е. Map‹String, dynamic›. Для этого мы выполним метод приведения. И полученное значение будет сохранено в переменной «convertedJsonObject».
  5. Теперь, когда у нас есть карта, мы передадим ее в качестве аргумента функции fromJson, которая возвращает объект Photo. И это должно происходить для всех значений. Более того, нам нужен список фотографий, а не просто фотография. И для этого мы используем
  6. И, наконец, мы сможем вернуть этот список.

Шаг 6:

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

Таким образом, мы будем использовать FutureBuilder. FutureBuilder, который состоит из двух очень важных свойств: future и builder.

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

Вам просто нужно определить эту переменную в функции build(_) объекта wer _NewAppState.

var futureBuilder = new FutureBuilder( future: obtainJson(), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return Text('Press button to start.'); case ConnectionState.active: return Text('Awaiting result...'); case ConnectionState.waiting: return Text('Awaiting result...'); case ConnectionState.done: if (snapshot.hasError) return Text('Error:${snapshot.error}'); return listViewBuilder(context, snapshot.data); default: return Text('Some error occurred'); } } );

Однако мы еще не определили функцию listViewBuilder(_,_). Итак, давайте выполним это на следующем шаге. Кроме того, эта функция вернет ListView.

Поэтому независимо от состояния подключения переменная futureBuilder всегда будет иметь значение Widget.

Шаг 7:

Теперь давайте определим функцию listViewBuilder(_,_).

Widget listViewBuilder(BuildContext context,List<dynamic> values) { return ListView.builder( itemBuilder: (BuildContext context, int index) { return ListTile( leading: Text((values[index].id).toString()), title: Text((values[index].title).toString()), subtitle: Text((values[index].thumbnailUrl).toString()), ); } ); }

Передаваемые значения являются не чем иным, как объектом Photo. Итак, мы можем легко получить доступ к значениям класса Photo, который состоит из id, .title и .thumbnailUrl. .toString() изменяет эти значения атрибутов на строку.

Шаг 8:

Последним и, возможно, очень важным шагом является использование виджета в переменной futureBuilder. И для этого вам нужно будет изменить тело wer Scaffold на:

Если мы могли что-то упустить, проверьте полный файл main.dart:

import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http;void main() => runApp(NewApp());class NewApp extends StatefulWidget { @override _NewAppState createState() => _NewAppState(); }class _NewAppState extends State<NewApp> { Future<List<Photo>> obtainJson() async { final response = await http.get('https://jsonplaceholder.typicode.com/photos'); String responseBody = response.body; dynamic jsonObject = json.decode(responseBody); final convertedJsonObject = jsonObject.cast<Map<String, dynamic>>(); List<Photo> list = convertedJsonObject.map<Photo>((json) => Photo.fromJson(json)).toList(); return list; } Widget listViewBuilder(BuildContext context, List<dynamic> values { return ListView.builder( itemBuilder: (BuildContext context, int index) { return ListTile( leading: Text((values[index].id).toString()), title: Text((values[index].title).toString()), subtitle: Text((values[index].thumbnailUrl).toString()), ); } ); } @override Widget build(BuildContext context) { var futureBuilder = new FutureBuilder( future: obtainJson(), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return Text('Press button to start.'); case ConnectionState.active: return Text('Awaiting result...'); case ConnectionState.waiting: return Text('Awaiting result...'); case ConnectionState.done: if (snapshot.hasError) return Text('Error: ${snapshot.error}'); return listViewBuilder(context, snapshot.data); default: return Text('Some error occurred'); } } ); return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: Center( child: futureBuilder, ), ), ); } }class Photo { int id; String title, thumbnailUrl; Photo({this.id, this.title, this.thumbnailUrl}); factory Photo.fromJson(Map<String, dynamic> json) { return Photo( id: json['id'] as int, title: json['title'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); } }

Первоначально опубликовано на https://codecarbon.com 17 ноября 2020 г.