fun newsDataToEntity(articleNetwork: ArticleNetwork): News {
val urlToImage = articleNetwork.urlToImage
val title = articleNetwork.title
val description = articleNetwork.description
val dataPublishedAt = articleNetwork.dataPublishedAt
val url = articleNetwork.url
return News(title, description, urlToImage, dataPublishedAt, url)
}
id у элементов должен отражать их назначение, а не быть просто копией типа элемента. Для примера recyclerView можно было бы назвать newsList или типо того. Почитай по различные подходы к наименованию элементов.
Общие моменты:
findViewById вещь крайне устаревшая и нерекомендуемая к использованию. Вместо этого лучше использовать viewBinding. Судя по подключенным библиотекам ты даже пытался это сделать (в build.gradle лежит implementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.4.6'). Почитай поподробнее про viewBinding, вещь полезная и весьма удобная.
Реализация SplashScreen (которая с котиками) весьма странная, особенно учитывая то, что для Android 12 выкатили новое SplashScreen API которое позволяет удобно настаивать SplashScreen. Google крайне рекомендует мигрировать с реализаций вроде твоей на это новое API. К примеру у меня на телефоне Android 12 и твой SplashScreen у меня не работает вообще.
Подробнее про SplashScreen APIтут и тут
activity_news_main.xml на вершине иерархии содержит ConstraintLayout в твоем случае его можно легко заменить на FrameLayout который быстрее ConstraintLayout из-за меньшего вызова метода measure() на своих child-ах. Почитай про разные типы контейнеров и их отличия в плане производительности.
То же самое относится и к activity_web.xml
При клике на retryButton в NewsActivity логика весьма странная, вместо того, чтобы завершать Activity и стартовать заново лучше было бы повторять запрос данных, примерно как при SwipeToRefresh тогда пользователю не будет показываться анимация завершения Activity.
Приложение не адаптировано под темную тему. Если на устройстве установлена темная тема, то карточки элементов в списке будут иметь темный фон, при этом текст заголовка тоже будет темный, из-за чего читать текст очень сложно. Почитай про то, как нужно обрабатывать тему на устройстве и адаптировать интерфейс под нее.
В проект подключено множество неиспользованных библиотек, например rxJava, хотя ты используешь Kotlin Coroutines. Наличие неиспользуемых библиотек замедляет сборку проекта. Лучше их убрать.
В NewsRemoteMediator можно обойтись без метода getLastRemoteKey. У state есть метод lastItemOrNull(), который фактически делает то же самое что и ты в своем методе.
Такие вещи лучше оборачивать в транзакционные блоки withTransaction. Для этого нужно в конструктор NewsRemoteMediator передать объект NewsDatabase и вызвать у него метод withTransaction в котором уже работать с бд. А в идеале вообще не передавать NewsDatabase в конструктор, а внедрять его через DI, ну об этом ниже.
Замечания по исполнению задания:
Dagger весьма сложная вещь для освоения, особенно для начинающих. В задании не говорилось использовать конкретно Dagger, есть более простые варианты. Например библиотека Hilt, являющаяся обёрткой над Dagger и существенно упрощающая работу с DI. Еще есть Koin тоже весьма интересный варианты работы с DI. Можешь почитать про их отличия тут
Касательно проблем с RemoteMediator могу посоветовать в первую очередь жестко определить размеры изображений у элементов списка. Из-за того, что при загрузке списка картинок еще нет на экран вмещается много элементов и APPEND срабатывает ложно, также из-за этого сам список выглядит плохо, потому что все картинки разные по высоте. Также у Picasso можно добавить Placeholder при отрисовке картинки, так элементы будут изначально занимать нужный размер на экране, а после того как изображение загрузится, оно заменит собой плейсхолдер. Примерно как тут
Также можно поиграться с параметром initialLoadSize в PagingConfig.
Ну и на крайний случай можно отвязаться от получения последнего элемента из PagingState и получать его из локальной базы данных. Например как тут
Добрый день.
Разделю ревью на какое-то подобие тем.
Начнем с простого - Code style:
В таких случаях можно обойтись без объявления возвращаемого типа и
return
. Получится что-то вроде этого:Подробнее тут.
Можно было бы записать как:
Или вообще как
Extension
id
у элементов должен отражать их назначение, а не быть просто копией типа элемента. Для примераrecyclerView
можно было бы назватьnewsList
или типо того. Почитай по различные подходы к наименованию элементов.Общие моменты:
findViewById
вещь крайне устаревшая и нерекомендуемая к использованию. Вместо этого лучше использоватьviewBinding
. Судя по подключенным библиотекам ты даже пытался это сделать (в build.gradle лежитimplementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.4.6'
). Почитай поподробнее проviewBinding
, вещь полезная и весьма удобная.Реализация
SplashScreen
(которая с котиками) весьма странная, особенно учитывая то, что для Android 12 выкатили новое SplashScreen API которое позволяет удобно настаиватьSplashScreen
. Google крайне рекомендует мигрировать с реализаций вроде твоей на это новое API. К примеру у меня на телефоне Android 12 и твой SplashScreen у меня не работает вообще. Подробнее проSplashScreen API
тут и тутactivity_news_main.xml
на вершине иерархии содержитConstraintLayout
в твоем случае его можно легко заменить наFrameLayout
который быстрееConstraintLayout
из-за меньшего вызова методаmeasure()
на своих child-ах. Почитай про разные типы контейнеров и их отличия в плане производительности.То же самое относится и к
activity_web.xml
При клике на
retryButton
вNewsActivity
логика весьма странная, вместо того, чтобы завершатьActivity
и стартовать заново лучше было бы повторять запрос данных, примерно как приSwipeToRefresh
тогда пользователю не будет показываться анимация завершенияActivity
.Приложение не адаптировано под темную тему. Если на устройстве установлена темная тема, то карточки элементов в списке будут иметь темный фон, при этом текст заголовка тоже будет темный, из-за чего читать текст очень сложно. Почитай про то, как нужно обрабатывать тему на устройстве и адаптировать интерфейс под нее.
В проект подключено множество неиспользованных библиотек, например
rxJava
, хотя ты используешьKotlin Coroutines
. Наличие неиспользуемых библиотек замедляет сборку проекта. Лучше их убрать.В
NewsRemoteMediator
можно обойтись без методаgetLastRemoteKey
. Уstate
есть методlastItemOrNull()
, который фактически делает то же самое что и ты в своем методе.В
NewsRemoteMediator
есть работа с бд -и
Такие вещи лучше оборачивать в транзакционные блоки
withTransaction
. Для этого нужно в конструктор NewsRemoteMediator передать объектNewsDatabase
и вызвать у него методwithTransaction
в котором уже работать с бд. А в идеале вообще не передаватьNewsDatabase
в конструктор, а внедрять его через DI, ну об этом ниже.Замечания по исполнению задания:
Dagger весьма сложная вещь для освоения, особенно для начинающих. В задании не говорилось использовать конкретно Dagger, есть более простые варианты. Например библиотека Hilt, являющаяся обёрткой над Dagger и существенно упрощающая работу с DI. Еще есть Koin тоже весьма интересный варианты работы с DI. Можешь почитать про их отличия тут
Касательно проблем с
RemoteMediator
могу посоветовать в первую очередь жестко определить размеры изображений у элементов списка. Из-за того, что при загрузке списка картинок еще нет на экран вмещается много элементов и APPEND срабатывает ложно, также из-за этого сам список выглядит плохо, потому что все картинки разные по высоте. Также уPicasso
можно добавитьPlaceholder
при отрисовке картинки, так элементы будут изначально занимать нужный размер на экране, а после того как изображение загрузится, оно заменит собой плейсхолдер. Примерно как тутТакже можно поиграться с параметром
initialLoadSize
вPagingConfig
.Ну и на крайний случай можно отвязаться от получения последнего элемента из
PagingState
и получать его из локальной базы данных. Например как тут