Создавайте страницы с более быстрой загрузкой с помощью этих стратегий

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

Когда дело доходит до вопроса,

Каков один из простых способов разбивки на страницы для декларативно созданного пользовательского интерфейса проекта Kotlin Multiplatform Mobile (KMM)?

Ответы могут быть разные, но точных ответов относительно практичности и надежности у нас нет. Чтение этой статьи позволит вам изучить ответ, который вы могли бы ожидать.

Требование

Рекомендуется понимать структуру проекта KMM. Если вы еще не знакомы с ним, пожалуйста, сначала прочтите его здесь. Также ожидается, что он будет знаком с декларативным пользовательским интерфейсом платформ Android (Jetpack Compose) и iOS (SwiftUI). Теперь давайте начнем с общего модуля.

Общий

Поскольку проект КММ модульный, мы начнем с общего модуля. Во-первых, нам нужен класс данных, состоящий из ответа API. Ответ API с разбивкой на страницы обычно содержит текущую отображаемую страницу, общее количество страниц и сообщение. Ниже приведен пример:

В приведенном выше классе данных page является текущей отображаемой страницей. Между тем, themessage — это сообщение о состоянии сервера, которое существует только в случае возникновения ошибки. Кроме того, у нас также есть totalPages, показывающий количество страниц, которые мы должны загрузить.

Чтобы лучше работать с результатом выборки API, рекомендуется обернуть результат в состояние. Ниже приведен пример состояния:

Приведенное выше состояние заключает ответ API и ошибку в общий модуль, поэтому нам просто нужно создать одну функцию в нашей модели общего представления, которая может возвращать оба возможных результата (ответ API или возникновение ошибки). Теперь давайте посмотрим, как модель общего представления вызывает API. Вот код:

В MovieListSharedViewModelвыше мы не применяем функцию try-catch, поскольку она была обработана в репозитории, поэтому loadMovieфункция выше просто вызовет результат. Это применяется, чтобы мы могли более эффективно вызывать функцию в рабочей области iOS. Обратитесь здесь, чтобы узнать больше.

Мы закончили работу с нашим общим модулем независимо от варианта использования и репозитория. Теперь мы можем обратиться к нашему модулю Android, чтобы начать реализацию разбивки на страницы для платформы Android.

Андроид

Декларативный пользовательский интерфейс платформы Android может быть реализован с помощью Jetpack Compose. Установить пагинацию в Jetpack Compose довольно просто. Мы можем использовать его библиотеку подкачки, которую легко реализовать. Для начала добавьте следующую зависимость в приложение Android Gradle.

implementation(“androidx.paging:paging-compose:1.0.0-alpha10”)

Теперь давайте создадим источник подкачки данных, который будет вызываться в нашей модели view:

В load функция выше вызывает функцию, которую мы сделали в общей модели view раньше. Чтобы собрать возвращаемый результат sharedViewModel.loadMovie, мы используем .last(), так как функция loadMovie обернута Flow. Наконец, чтобы сделать повторно используемые условия результата, логика возврата обрабатывается в классе PagingHelper ниже:

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

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

В приведенном выше примере список инициализируется напрямую. Однако, если мы хотим оставить его пустым при инициализации модели представления, мы можем установить его равным var list: Flow<PagingData<Movie>> = flowOf(PagingData.empty()). Эта инициализация также позволяет нам изменять список по мере необходимости.

Наконец, в нашей составной функции мы можем вызвать список, собрав список в нашей модели представления с помощью viewModel.list.collectAsLazyPagingItems(). Чтобы увидеть, как это реализовано, проверьте код ниже:

Однако в списке есть CombinedLoadStates, которые нужно вызвать для обработки ошибки. Опять же, чтобы иметь многоразовое представление постраничного просмотра, которое хранит свои состояния ошибок, я создал собственный держатель представления постраничного просмотра следующим образом:

Наконец, теперь мы можем попробовать наше приложение для Android. Ниже приведен скриншот, если мы запустим код:

iOS

Мы заставили разбиение на страницы работать в Android, и теперь пришло время превратить его в Xcode для реализации в iOS. Давайте начнем с создания модели представления или наблюдаемого класса, который будет использоваться в качестве состояния в нашей конфигурации представления. Как и в Android, модель представления должна иметь как минимум список данных, текущую отображаемую страницу и выбрасываемый объект, который в данном случае я прямо установил как сообщение об ошибке. Модель представления должна быть следующей:

В приведенном выше примере у нас есть состояние загрузки, а именно loadingPage, которое можно использовать, когда нам нужно использовать его в нашей конфигурации пользовательского интерфейса. Кроме того, также устанавливается сообщение об ошибке, когда у нас есть либо IOException, либо сообщение о состоянии с сервера. В качестве дополнительной информации, sharedViewModel инициализируется в MovieModule, настроенном в iOS main проекта KMM. Обратитесь здесь, чтобы узнать больше.

Наконец, самое важное здесь то, что мы инициализируем список не так, как в модели представления Android, поскольку нам нужно использовать функцию append для добавления списка. Это все, что нам нужно для конфигурации модели представления. Теперь мы можем приступить к созданию нашей функции пользовательского интерфейса.

При отображении списка данных подкачки в SwiftUI мы должны использовать LazyVStack для повышения производительности. Кроме того, нам нужно показать загружаемое представление на основе состояния isLastPage, которое у нас есть в модели представления. Это должно использоваться, чтобы указать, что состояние прокрутки достигло последнего элемента.

Из приведенного выше кода мы можем сделать простое предположение о том, как модель представления вызывает функцию loadPage в представлении загрузки списка, когда оно появляется. Однако, как только мы дойдем до последней страницы, загрузочное представление не появится, и модель представления не будет вызывать функцию loadPage.

Что дальше? Да, все готово, и теперь мы можем запустить приложение. Наше приложение должно отображать данные пейджинга следующим образом:

Заключение

Конечно, при работе над мультиплатформенным проектом мы ожидаем, что для повышения эффективности у нас будет код «два в одном». В этом проекте мы применили функцию загрузки страницы в модели представления общего списка фильмов, которую мы можем использовать как в источнике данных подкачки Android, инициализированном в модели представления Android, так и в модели представления iOS. Однако мы обсудим только основные функции, необходимые для реализации разбиения на страницы.

Чтобы получить более полную реализацию, обратитесь к реальному проекту ниже: