Как получить данные из интернета?

kak-poluchit-dannye-interneta

Получение данных из Интернета необходимо для большинства приложений. К счастью, Dart и Flutter предоставляют инструменты, такие как пакет http, для этого типа работы.

Для этого нужно:

  1. Добавьте пакет http.
  2. Сделайте сетевой запрос, используя пакет http.
  3. Преобразуйте ответ в пользовательский объект Dart.
  4. Получить и отобразить данные с помощью Flutter.

 

  1. Добавьте пакет http

Пакет http обеспечивает самый простой способ извлечения данных из Интернета.

Чтобы установить пакет http, добавьте его в раздел зависимостей файла pubspec.yaml. Вы можете найти последнюю версию http пакета pub.dev.

dependencies:
  http: <latest_version>

Импортируйте пакет http.

import 'package:http/http.dart' as http;
  1. Сделать сетевой запрос

Здесь показано, как извлечь образец альбома из JSONPlaceholder с помощью метода http.get ().

Future<http.Response> fetchAlbum() {
  return http.get('https://jsonplaceholder.typicode.com/albums/1');
}

Метод http.get () возвращает Future, содержащий Response.

  • Future – основной класс Dart для работы с асинхронными операциями. Объект Futureпредставляет потенциальное значение или ошибку, которая будет доступна в будущем.
  • Класс http.Response содержит данные, полученные при успешном вызове http.
  1. Конвертировать ответ в пользовательский объект Dart

Хотя сделать сетевой запрос легко, работа с необработанным Future<http.Response> не очень удобна. Чтобы сделать вашу жизнь проще, преобразуйте http.Response в объект Dart.

Создать класс Album

Сначала создайте класс Album, который содержит данные из сетевого запроса. Он включает конструктор, который создает Album из JSON.

Преобразование JSON вручную –  единственный вариант.

class Album {
  final int userId;
  final int id;
  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

Преобразовать http.Response в Album

Теперь используйте следующие шаги, чтобы обновить функцию fetchAlbum () и вернуть <Future<Album>:

  1. Преобразуйте тело ответа в JSON Map с помощью пакета dart: convert.
  2. Если сервер возвращает ответ OK с кодом состояния 200, преобразуйте JSON Map в Album, используя метод fromJson ().
  3. Если сервер не возвращает ответ OK с кодом состояния 200, выдается исключение. (Даже в случае ответа сервера «404 Не найдено» выведите исключение. Не возвращайте null.)
Future<Album> fetchAlbum() async {
  final response = await http.get('https://jsonplaceholder.typicode.com/albums/1');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(json.decode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

Теперь у вас есть функция, которая загружает альбом из Интернета.

  1. Получить данные

Вызовите метод fetch () в методах initState () или didChangeDependencies ().

Метод initState () вызывается ровно один раз, и никогда больше. Если вы хотите иметь возможность перезагрузить API в ответ на изменение InheritedWidget, поместите вызов в метод didChangeDependencies().

class _MyAppState extends State<MyApp> {
  Future<Album> futureAlbum;

  @override
  void initState() {
    super.initState();
    futureAlbum = fetchAlbum();
}
Future используется на следующем этапе.
  1. Показать данные

Для отображения данных на экране используйте виджет FutureBuilder. Виджет FutureBuilder идет с Flutter и упрощает работу с асинхронными источниками данных.

Вы должны предоставить два параметра:

  1. Future, с которым вы хотите работать. В этом случае будущее возвращается из функции fetchAlbum ().
  2. Функция builder, которая сообщает Flutter, что показывать, в зависимости от состояния Future: загрузка, успех или ошибка.

Обратите внимание, что snapshot.hasData возвращает true только в том случае, если значение данных snapshot не null. Вот почему функция fetchAlbum должна выдавать исключение даже в случае ответа сервера «404 Not Found». Если fetchAlbum возвращает null, то индикатор загрузки отображается бесконечно.

FutureBuilder<Album>(
  future: futureAlbum,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return Text(snapshot.data.title);
    } else if (snapshot.hasError) {
      return Text("${snapshot.error}");
    }

    // By default, show a loading spinner.
    return CircularProgressIndicator();
  },
);

Почему fetchAlbum() вызывается в initState()?

Хотя это удобно, не рекомендуется помещать вызов API в метод build().

Flutter вызывает метод build() каждый раз, когда ему нужно что-то изменить в представлении, и это происходит на удивление часто. Оставив вызов fetch в вашем методе build(), вы переполняете API ненужными вызовами и замедляете работу вашего приложения.

Полный пример

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum() async {
  final response =
      await http.get('https://jsonplaceholder.typicode.com/albums/1');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(json.decode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

class Album {
  final int userId;
  final int id;
  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<Album> futureAlbum;

  @override
  void initState() {
    super.initState();
    futureAlbum = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Album>(
            future: futureAlbum,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.title);
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }

              // By default, show a loading spinner.
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}


.

  • May 25, 2020