Android MVVM+coroutine+retrofit+flow+hilt

Android MVVM+coroutine+retrofit+flow+hilt

概述

在这里插入图片描述

代码结构:

在这里插入图片描述

依赖注入层

数据库:

@Module
@InstallIn(SingletonComponent::class)
class DBModule {
   

    @Singleton
    @Provides
    fun provideDB(application: Application): AppDatabase {
   
        return AppDatabase.getDatabase(application)
    }

    @Singleton
    @Provides
    fun provideCacheDao(db: AppDatabase): CacheDao {
   
        return db.cacheDao()
    }
}

网络请求:

@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {
   

    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
   
        return HttpManager.okHttpClient
    }

    @Singleton
    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
   
        return HttpManager.retrofit
    }

    @Singleton
    @Provides
    fun provideLoginApi(retrofit: Retrofit): LoginApi {
   
        return retrofit.create(LoginApi::class.java)
    }

    @Singleton
    @Provides
    fun provideArticleApi(retrofit: Retrofit): ArticleApi {
   
        return retrofit.create(ArticleApi::class.java)
    }
}

数据层

open class BaseModel {
   

    @Inject
    lateinit var cacheHelper: CacheHelper

    fun <T> requestForResult(block: suspend () -> BaseResponse<T>): Flow<ResultState<T>> {
   
        return flow<ResultState<T>> {
   
            val response = block()
            if (response.isSuccessful()) {
   
                emit(ResultState.Success(response.data!!))
            } else {
   
                val serverException = ServerException(response.errorCode, response.errorMsg)
                val e = ExceptionHandler.handleException(serverException)
                emit(ResultState.Error(e, e.displayMessage))
            }
        }.flowOn(Dispatchers.IO)
            .catch {
   
                val e = ExceptionHandler.handleException(it)
                emit(ResultState.Error(e, e.displayMessage))
            }
    }

    suspend fun <T> requestForResult(
        cacheName: String,
        cacheBlock: () -> T?,
        block: suspend () -> BaseResponse<T>
    ): Flow<ResultState<T>> {
   
        return flow {
   
            val cacheData = cacheBlock()
            cacheData?.let {
   
                emit(ResultState.Success(cacheData, true))
            }

            val response = block()
            if (response.isSuccessful()) {
   
                cacheHelper.saveCache(cacheName, response.data!!)
                emit(ResultState.Success(response.data, false))
            } else {
   
                val serverException = ServerException(response.errorCode, response.errorMsg)
                val e = ExceptionHandler.handleException(serverException)
                emit(ResultState.Error(e, e.displayMessage))
            }
        }.flowOn(Dispatchers.IO)
            .catch {
   
                val e = ExceptionHandler.handleException(it)
                emit(ResultState.Error(e, e.displayMessage))
            }
    }
}
class ArticleModel @Inject constructor() : BaseModel() {
   

    @Inject
    lateinit var articleApi: ArticleApi

    suspend fun getArticleList(): Flow<ResultState<ArrayList<ArticleBean>>> {
   
        val cacheName = "article_list"
        return requestForResult(cacheName, {
   
            cacheHelper.getCache<ArrayList<ArticleBean>>(
                cacheName, object : TypeToken<ArrayList<ArticleBean>>() {
   }.type
            )
        }, {
   
            articleApi.getArticleList()
        })
    }
}

视图层

abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
   
    private lateinit var _mViewBinding: VB
    protected val mViewBinding get() = _mViewBinding

    override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        _mViewBinding = createViewBinding()
        setContentView(_mViewBinding.root)
        initViews()
        initData(savedInstanceState)
    }

    abstract fun createViewBinding(): VB

    abstract fun initViews()

    abstract fun initData(savedInstanceState: Bundle?)
}

@AndroidEntryPoint
class ArticleListActivity : BaseActivity<ActivityArticleListBinding>() {
   
    private val mList = arrayListOf<ArticleBean>()
    private val articleListViewModel by viewModels<ArticleViewModel>()
    private val progressDialog: ProgressDialog by lazy {
   
        ProgressDialog(this).apply {
   
            setMessage("加载中")
        }
    }

    override fun createViewBinding(): ActivityArticleListBinding {
   
        return ActivityArticleListBinding.inflate(layoutInflater)
    }

    override fun initViews() {
   

    }

    override fun initData(savedInstanceState: Bundle?) {
   
        mViewBinding.rvArticleList.adapter = ArticleAdapter(this, mList)

        mViewBinding.btnGetArticleList.setOnClickListener {
   
            getArticleList()
        }
        observe()
    }

    private fun getArticleList() {
   
        articleListViewModel.getArticleList()
    }

    private fun observe() {
   
        lifecycleScope.launch {
   
            repeatOnLifecycle(Lifecycle.State.RESUMED) {
   
                articleListViewModel.articleFlow.collect {
   
                    when (it) {
   
                        is ResultState.Loading -> showLoading()
                        is ResultState.Error -> {
   
                            showToast(it.message)
                            hideLoading()
                        }
                        is ResultState.Success -> {
   
                            hideLoading()
                            updateUI(it.data)
                        }
                    }
                }
            }
        }
    }

    private fun updateUI(list: ArrayList<ArticleBean>?) {
   
        mList.clear()
        if (list != null) {
   
            mList.addAll(list)
        }
        mViewBinding.rvArticleList.adapter!!.notifyDataSetChanged()
    }

    private fun showLoading() {
   
        progressDialog.show()
    }

    private fun hideLoading() {
   
        progressDialog.hide()
    }
}

模型视图层

open class BaseViewModel : ViewModel() {
   

    fun launchMain(block: suspend CoroutineScope.() -> Unit) {
   
        viewModelScope.launch(Dispatchers.Main) {
   
            block()
        }
    }

    fun launchIO(block: suspend CoroutineScope.() -> Unit) {
   
        viewModelScope.launch(Dispatchers.IO) {
   
            block()
        }
    }

    fun launchDefault(block: suspend CoroutineScope.() -> Unit) {
   
        viewModelScope.launch(Dispatchers.Default) {
   
            block()
        }
    }
}
@HiltViewModel
class ArticleViewModel @Inject constructor(
    private val articleModel: ArticleModel
) : BaseViewModel() {
   
    private val _articleFlow =
        MutableStateFlow<ResultState<ArrayList<ArticleBean>>>(ResultState.None)
    val articleFlow get() = _articleFlow.asStateFlow()

    fun getArticleList() {
   
        launchIO {
   
            articleModel.getArticleList()
                .onStart {
   
                    _articleFlow.value = ResultState.Loading
                }
                .collect {
   
                    _articleFlow.value = it
                }
        }
    }
}

代码下载

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-08 21:06:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-08 21:06:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-08 21:06:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-08 21:06:03       18 阅读

热门阅读

  1. GO设计模式——10、组合模式(结构型)

    2023-12-08 21:06:03       25 阅读
  2. 【工具】机器之间传输文件的常用方式

    2023-12-08 21:06:03       37 阅读
  3. Nump数组的拼接详细教程

    2023-12-08 21:06:03       32 阅读
  4. mysql获取时间异常

    2023-12-08 21:06:03       40 阅读
  5. TypeScript中泛型对象、泛型类

    2023-12-08 21:06:03       39 阅读
  6. 【python】vscode中选择虚拟环境venv

    2023-12-08 21:06:03       37 阅读
  7. Linux DAC权限的简单应用

    2023-12-08 21:06:03       30 阅读
  8. 做题笔记:SQL Sever 方式做牛客SQL的题目--VQ34

    2023-12-08 21:06:03       31 阅读