Как сохранить данные в базу данных после извлечения данных с сервера, используя комнату в kotlin сопрограмм? - PullRequest
0 голосов
/ 01 апреля 2020

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

ниже моего SportNewsDatabase.kt

@Database(entities = [Article::class], version = 1, exportSchema = false)
abstract class SportNewsDatabase : RoomDatabase() {

    abstract fun sportNewsDao(): SportNewsDao

    companion object {
        private var instance: SportNewsDatabase? = null
        fun getInstance( context: Context): SportNewsDatabase? {
            if (instance == null) {
                synchronized(SportNewsDatabase::class.java) {
                    instance = Room.databaseBuilder(context.applicationContext, SportNewsDatabase::class.java, "article_database")
                        .fallbackToDestructiveMigration()
                        .build()
                }
            }
            return instance
        }
    }


}

ниже SportNewsDao.kt

@ Dao interface SportNewsDao {

@Query("SELECT * FROM  article")
fun getAllData(): LiveData<List<Article>>

@Insert
 suspend fun addAll(article: List<Article>)


@Update
 suspend fun updateArticle(article: Article)

@Delete
 suspend fun deleteArticle(article: Article)

}

below my repository class
interface NewsRepository {
    // Suspend is used to await the result from Deferred
    suspend fun getNewsList(): UseCaseResult<List<Article>>
     var sportNewsDao: SportNewsDao
}



fun insertArticle(article: List<Article>){
    val insertArticles 
}


@Suppress("UNCHECKED_CAST")
class NewsRepositoryImpl(private val sportsNewsApi: SportNewsInterface) : NewsRepository {
    override suspend fun getNewsList(): UseCaseResult<List<Article>> {

        return try {
            val result = sportsNewsApi.getNewsAsync().body()!!.articles

            UseCaseResult.Success(result)
        } catch (ex: Exception) {
            UseCaseResult.Error(ex)
        }
    }
}

ниже MainViewModel.kt, где я использую Kotlin сопрограммы

@Suppress("UNCHECKED_CAST")
class MainViewModel(val newsRepository: NewsRepository) : ViewModel(), CoroutineScope {
    // Coroutine's background job
    val job = Job()
    // Define default thread for Coroutine as Main and add job
    override val coroutineContext: CoroutineContext = Dispatchers.Main + job

    val showLoading = MutableLiveData<Boolean>()
    val sportList = MutableLiveData<List<Article>>()
    val showError = SingleLiveEvent<String>()

    fun loadNews() {
        // Show progressBar during the operation on the MAIN (default) thread
        showLoading.value = true
        // launch the Coroutine
        launch {
            // Switching from MAIN to IO thread for API operation
            // Update our data list with the new one from API
            val result = withContext(Dispatchers.IO) {
                newsRepository?.getNewsList()
            }
            // Hide progressBar once the operation is done on the MAIN (default) thread
            showLoading.value = false
            when (result) {

                is UseCaseResult.Success<*> -> {
                    sportList.value = result.data as List<Article>
                }
                is Error -> showError.value = result.message
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        // Clear our job when the linked activity is destroyed to avoid memory leaks
        job.cancel()
    }
}

1 Ответ

0 голосов
/ 29 апреля 2020

@ sashabeliy

Привет, я думаю, что у меня есть решение вашей проблемы, но я не эксперт по mvvm и сопрограммам, поэтому, если у кого-то есть лучшее решение, я беру его :)

Для моего приложения я запускаю загрузку в основном потоке и только когда получаю ответ, использую Dispatchers.IO для вставки в комнату полученных данных.

В ViewModel

fun downLoadPDV(last_update : String) : LiveData<List<PDV>> { return repositoryPDV.downloadPDV(last_update) }

В репозитории

fun downloadPDV(last_update : String ): LiveData<List<PDV>> {
    val mutableLiveData: MutableLiveData<List<PDV>> = MutableLiveData()
    val apiService: ApiInterface = RetrofitClient.getRetrofitClient().create(ApiInterface::class.java)

    apiService.CallListPDV(last_update)?.enqueue(object :
        Callback<List<PDV>> {
        override fun onResponse(
            call: Call<List<PDV>>,
            response: Response<List<PDV>>
        ) {
            Log.e(ContentValues.TAG, "Download PDV Success => $response")

            if (response.isSuccessful && response.body() != null) {

                mutableLiveData.setValue(response.body());

                GlobalScope.launch(Dispatchers.IO) {
                    for (pdv in response.body()!!) {
                        insertPDV(pdv)
                    }
                }
            }
        }

        override fun onFailure(call: Call<List<PDV>>, t: Throwable) {
            Log.e(ContentValues.TAG, "[Error] Download PDV Fail --> $call")
        }
    })
    return mutableLiveData
}

Я возвращаю Загрузку данных для обновления пользовательского интерфейса и информирую пользователя о количестве загруженных элементов

...