基于MVVM架构:如何将Retrofit请求的Genre列表存入Room数据库
MVVM+Room+Retrofit 实现网络列表存储与LiveData获取
以下是从网络拉取Genre列表并存入Room,再通过LiveData给UI层提供数据的完整实现方案,核心逻辑集中在Repository层:
1. 定义Room实体类
创建对应数据库表的实体,标记主键和表名:
@Entity(tableName = "genres") data class Genre( @PrimaryKey val id: Int, val name: String )
2. 编写Room Dao接口
Dao层定义数据库操作,包含批量插入(冲突时替换)和获取LiveData列表的方法:
@Dao interface GenreDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(genres: List<Genre>) @Query("SELECT * FROM genres") fun getAllGenres(): LiveData<List<Genre>> }
3. 实现Retrofit网络接口
定义获取Genre列表的API服务,以及Retrofit实例初始化:
interface GenreApiService { @GET("genres") // 替换为实际API路径 suspend fun getGenresFromNetwork(): Response<List<Genre>> } // Retrofit实例(建议封装为单例) val retrofit = Retrofit.Builder() .baseUrl("https://your-api-domain.com/") // 替换为实际BaseUrl .addConverterFactory(GsonConverterFactory.create()) .build() val genreApiService = retrofit.create(GenreApiService::class.java)
4. 核心:Repository层实现
Repository作为数据统一入口,处理网络请求、数据库存储,并对外暴露LiveData:
class GenreRepository( private val genreDao: GenreDao, private val genreApiService: GenreApiService ) { // 直接暴露数据库的LiveData,UI层可观察 val allGenres: LiveData<List<Genre>> = genreDao.getAllGenres() // 刷新逻辑:拉取网络数据后存入数据库 suspend fun refreshGenres() { try { val response = genreApiService.getGenresFromNetwork() response.body()?.takeIf { response.isSuccessful }?.let { genreDao.insertAll(it) } } catch (e: Exception) { // 这里可添加异常处理,比如日志记录、状态通知 e.printStackTrace() } } }
5. ViewModel层对接Repository
ViewModel通过协程调用Repository的刷新方法,同时将LiveData暴露给UI:
class GenreViewModel( private val repository: GenreRepository ) : ViewModel() { val allGenres = repository.allGenres fun refreshGenres() { viewModelScope.launch { repository.refreshGenres() } } } // ViewModel工厂类(用于注入Repository依赖) class GenreViewModelFactory( private val repository: GenreRepository ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(GenreViewModel::class.java)) { @Suppress("UNCHECKED_CAST") return GenreViewModel(repository) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
6. UI层观察数据
在Activity/Fragment中初始化ViewModel,观察LiveData并更新UI:
class GenreActivity : AppCompatActivity() { private lateinit var viewModel: GenreViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_genre) // 初始化数据库、Repository和ViewModel(实际项目建议用Hilt等DI框架) val db = AppDatabase.getInstance(application) val repository = GenreRepository(db.genreDao(), genreApiService) viewModel = ViewModelProvider(this, GenreViewModelFactory(repository))[GenreViewModel::class.java] // 观察数据变化,更新UI viewModel.allGenres.observe(this) { genres -> updateGenreList(genres) } // 触发首次数据加载 viewModel.refreshGenres() } private fun updateGenreList(genres: List<Genre>) { // 实现RecyclerView或其他UI组件的更新逻辑 } }
关键注意事项
- 所有数据库和网络操作必须在协程中执行,Room的
suspend方法和Retrofit的suspend方法会自动切换到后台线程。 - Repository完全隔离数据来源,ViewModel和UI层无需关心数据是来自网络还是本地,符合MVVM的解耦思想。
- Room返回的
LiveData会自动监听数据库变化,数据更新时主动通知UI,无需手动触发刷新。 - 可扩展:如果需要给UI展示加载/错误状态,可以用密封类封装数据状态,在Repository中返回
LiveData<Resource<List<Genre>>>。
内容的提问来源于stack exchange,提问作者zulu_papa
相关产品推荐
相关产品推荐

