#android #database #kotlin #repository-pattern #android-livedata
#Android #База данных #kotlin #репозиторий-шаблон #android-livedata
Вопрос:
Я новичок в программировании на Android и хочу попробовать изучить лучшие практики. Мое первое приложение, которое я создаю, — это приложение для подкастов для отображения подкастов из rss-канала и их воспроизведения. То, что у меня есть до сих пор, работает, но я знаю, что могу заставить его работать лучше.
Я использую базу данных Room с шаблоном репозитория, что может быть излишним, потому что мне, вероятно, не нужно сохранять список подкастов при смерти приложения, если я просто собираюсь повторно проанализировать канал при запуске. В моем классе репозитория я вызываю свой класс FetchRSS для выполнения сетевого вызова в init{ }
блоке, который возвращает a List<Podcast>
.
Я знаю, что я что-то не так делаю.
В моем PodcastDao я должен использовать @Insert(onConflict = OnConflictStrategy.REPLACE)
, потому что база данных уже существует, и я получаю ошибку SQL 1555 относительно повторяющихся идентификаторов первичного ключа. По логике вещей, было бы лучше проверить, есть ли добавляемая запись уже в базе данных, но я не уверен, как это сделать. Или, что нелогично, очистить базу данных при смерти приложения, но тогда зачем вообще беспокоиться о базе данных. В идеале я хотел бы иметь функцию обновления (даже если RSS обновляется не чаще двух раз в неделю), но я не уверен, как лучше это сделать.
Если у кого-нибудь есть какие-либо мысли об улучшении этого или хорошая книга для изучения Android, я был бы внимателен. Большое спасибо всем, кто нашел время, чтобы посмотреть на это!
PodcastDao.kt
@Dao
interface PodcastDao {
@Query("SELECT * FROM podcast") // get everything from the database
fun getPodcasts(): LiveData<List<Podcast>>
@Query("SELECT * FROM podcast WHERE id=(:id)") // get the specific podcast
fun getPodcast(id: String): LiveData<Podcast?>
// @Insert(onConflict = OnConflictStrategy.REPLACE)
// fun addPodcasts(podcasts: LiveData<List<Podcast>>)
// this causes a build error with the generated PodcastDao.java file
// logcat error: Type of the parameter must be a class annotated with @Entity or a collection/array of it.
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun addPodcast(podcast: Podcast)
}
PodcastRepository.kt
class PodcastRepository private constructor(context: Context) {
private lateinit var podcasts: List<Podcast>
init {
CoroutineScope(Dispatchers.Main).launch {
podcasts = FetchRSS().fetchRss() // executes on Dispatchers.IO and returns parsed rss List<Podcast>
// this seems silly to add them one at a time, especially since the list is rather large
for (pod in podcasts) {
addPodcast(pod)
}
//it seems a better choice to dump the full list into the database at once
//however I can't figure out how to put the List<Podcast> into a LiveData<List<Podcast>> object
//or maybe I'm misunderstanding something about LiveData<>
//addPodcasts(podcasts)
}
}
suspend fun addPodcast(podcast: Podcast){
withContext(Dispatchers.IO){
podcastDao.addPodcast(podcast)
}
// this needs to receive the LiveData<List<Podcast>>, or a List<Podcast> and cram it into LiveData<>?
// suspend fun addPodcasts(podcasts: LiveData<List<Podcast>>) {
// withContext(Dispatchers.IO){
// podcastDao.addPodcasts(podcasts)
// }
// }
}
Ответ №1:
fun addPodcasts(podcasts: LiveData<List<Podcast>>)
должно быть
fun addPodcasts(podcasts: <List<Podcast>>)
Итак, теперь вы можете вызывать podcastDao.addPodcasts(podcasts)
(where podcasts
имеет тип List<Podcast>>
) из своего репозитория вместо того, чтобы вставлять их один за другим через цикл for .
Вы не можете вставить LiveData в Room, только объекты, помеченные @Entity
. Однако запрос может возвращать LiveData со списком этих объектов. Вы также можете вернуть только список.
Комментарии:
1. Сработало как шарм. На всякий случай я удалил свою базу данных и воссоздал ее с помощью
addPodcasts(podcasts)