Найти в Дзене
Тарасов

Flutter и Rest Api. Экран с загрузкой.

Оглавление

Непростительный косяк любого приложения или вообще любого графического интерфейса - это зависания. Про то, что интерфейс может зависнуть на время загрузки данных из интернета или на время отрисовки экрана мы уже не говорим. В большинстве случаев данные грузятся и отображаются за микросекунды и в идеальном вакууме пользователь даже не заметит загрузки. Но есть множество факторов не зависящих от разработчика, из-за которых время загрузки может увеличиться до секунд или даже десятков секунд. Что же делать, чтобы пользователь "не заскучал" и не начал думать, что приложение не работает и надо его перезапустить или даже переустановить, а лучше просто удалить ?

Эта статья является продолжением статьи

Как подружить Flutter с Rest Api
Полный.Застрял.Разработать()17 марта 2023

поэтому метод загрузки данных мы возьмем от туда.

Начинаем

Сначала создадим экран weather_page.dart - это класс наследованный от StatefulWidget - от класса со своим состоянием... Если вы хотите, чтобы я написал статью про базовые классы Flutter - напишите об этом комментарий.

Выглядит он так

-2

В файле main.dart делаем наш экран домашним

home: WeatherPage()

Создаем экземпляр класса для работы с api. А также экземпляр объекта в котором будет храниться результат вызова метода api.

!Важно Стоит обратить внимание на то, что тип возвращаемый методом getWeather() - это Future. Future это не объект, а состояние асинхронной операции.
!Комментарий, для самых интересующихся Во Flutter нет такого понятия, как многопоточность. Все работает на основе прерывания. Так работает процессор. Выполняя несколько операций параллельно - на самом деле процессор, например когда данные пишутся в память и его участие не нужно, переходит ко второй операции, а когда он не нужен во второй операции, то переходит к первой. Многопоточность в современных вычислительных машинах работает за счет многоядерных процессоров, где каждое ядро это отдельный процессор. Во Flutter нельзя одновременно и интерфейс рисовать и запрос отправлять - поэтому появилось понятие асинхронность и два волшебных слова async await. С помощью async мы говорим компилятору о том, что в этом методе будет точка прерывания выполнения, а с помощью await говорим где именно. Выглядит условно так - выполняется вызванный метод и как только доходим до await дальше метод не выполняется мы занимаемся другой задачей, например рисуем интерфейс, как только дорисовали возвращаемся к await и если метод рядом с await выполнился мы продолжаем выполнять метод вызванный изначально.

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

!Заметка В статье я буду использовать стандартный виджет анимации загрузки. Сегодня более привычным является загрузка skeleton или более правильно shimmer. Когда очертания финального экрана переливаются серым. Не будем на этом останавливаться, если интересно есть официальный туториал, о том как это сделать
Create a shimmer loading effect

Сам вызов метода выглядит следующим образом. Пройдемся построчно

-3

строка 11 - создаем экземпляр класса для работы с Api.

строка 12 - создаем объект, в котором будет храниться состояние асинхронного вызова Api.

!Важно. объект response помечен, как late. Это особенность null safety реализации в dart. В любой момент времени у объекта должно быть значение, или он должен быть помечен, как nullable. Кодовым словом late мы говорим компилятору следующее - мы гарантируем, что к моменту вызова метода build() у этого объекта будет значение. И собственно в момент инициализации состояния нашего экрана initState() (а метод инициализации в жизненном цикле виджетов вызывается первым) мы устанавливаем значение для объекта response.

строка 15 - мы переназначаем метод initState(), ну или точнее дополняем своей логикой, перед этим вызывая оригинал.

строка 18 - мы вызываем метод getWeather() сохраняя его состояние в переменной response.

Окей

Экран сделали. Метод вызвали. Что дальше ? Как нам обработать состояния асинхронной операции ?

Для этого во Flutter есть специальный виджет FutureBuilder. Выглядеть будет так

-4

строка 24 - добавляем FutureBuilder в дерево виджетов

строка 25 - говорим, где состояние за которым нужно следить

строка 26 - создаем переменную, в которой храним - загрузились данные или нет

!Заметка. В рамках нашей задачи это необязательно, можно обойтись просто проверкой флага snapshot.hasData вместо isReady. Но в будущем, когда необходимо будет добавить возможность запросить данные заново, в нашем объекте будут продолжать храниться данные, просто когда асинхронный метод выполнится они обновятся, но триггера для запуска анимации загрузки не будет, соответсвенно мы получим подвисший интерфейс. На помощь приходит свойство connectionState, которое в момент перезапуска Future будет либо waiting, либо active.

строка 30 - наши данные загрузились - выводим на экран

строка 34 - произошла ошибка - выводим ошибку

строка 38 - ни одно из условий выше не отработало показываем загрузку

Получится следующее

-5

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

Flutter и Rest Api. Отладка тестами.
Полный.Застрял.Разработать()18 марта 2023

Пишите вопросы в комментариях, ставьте лайки и подписывайтесь на канал. Спасибо.