Android MVVM+coroutine+retrofit+flow+hilt

文章目录

  • 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
                }
        }
    }
}

代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/220339.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣第374场周赛题解

这一场周赛的题目是比较难的一次&#xff0c;写了1个多小时就写了两个题目。 首先第一题&#xff1a; 纯水题&#xff0c;遍历然后进行一下判断就可以解决了。这边就不放代码了。 第二题&#xff1a; 这个题目&#xff0c;我觉得难度非常大&#xff0c;其实代码量也不大都是很…

C语言--每日选择题--Day36

第一题 1. 以下关于指针的说法,正确的是() A&#xff1a;int *const p 与 int const *p等价 B&#xff1a;const int *p 与 int *const p等价 C&#xff1a;const int *p 与 int const *p 等价 D&#xff1a;int *p[10] 与 int (*p)[10] 等价 答案及解析 C const 在*的左侧&…

Hadoop学习笔记(HDP)-Part.02 核心组件原理

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Java操作Excel之 POI介绍和入门

POI是Apache 提供的一个开源的Java API&#xff0c;用于操作Microsoft文档格式&#xff0c;如Excel、Word和PowerPoint等。POI是Java中处理Microsoft文档最受欢迎的库。 截至2023/12&#xff0c; 最新版本时 POI 5.2.5。 JDK版本兼容 POI版本JDK版本4.0及之上版本> 1.83.…

【面试】Java最新面试题资深开发-JVM第一弹

问题一&#xff1a;Java中的垃圾回收机制 在Java中&#xff0c;垃圾回收是如何工作的&#xff0c;可以简要描述一下垃圾回收的算法有哪些吗&#xff1f; 在Java中&#xff0c;垃圾回收是一种自动管理内存的机制&#xff0c;它负责识别不再被程序引用的对象并释放其占用的内存…

有趣的代码——有故事背景的程序设计3

这篇文章再和大家分享一些有“背景”的程序设计&#xff0c;希望能够让大家学到知识的同时&#xff0c;对编程学习更感兴趣&#xff0c;更能在这条路上坚定地走下去。 目录 1.幻方问题 2.用函数打印九九乘法表 3.鸡兔同笼问题 4.字数统计 5.简单选择排序 1.幻方问题 幻方又…

力扣101. 对称二叉树(递归法,迭代法,层次遍历法)

题目&#xff1a; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 代码及详细注释&…

⭐ Unity里 用Shader 去做实时动态绿幕抠图

1.先看一下效果 a.这是背景图片 b.抠完图之后(这里用的是扣去白色的) 2.shader代码如下 Shader "UniversalChromaKey" {Properties{_MainTex("Base (RGB)", 2D) "white" {}_Sens("Sensibilidad", Range(0,.9)) .3_Cutoff("R…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好&#xff0c;我是giszz. AI做图真是太爽了&#xff0c;解放生产力&#xff0c;发展生产力。 但是&#xff0c;你是不是也总疑惑&#xff0c;为什么别人的图&#xff0c;表现力那么丰富呢&#xff0c;而且指哪打哪&#xff0c;要…

模拟电路学习笔记(一)之芯片篇(持续更新)

模拟电路学习笔记&#xff08;一&#xff09;之芯片篇&#xff08;持续更新&#xff09; 1.CD4047BE芯片 CD4047是一种包含高电压的多谐振荡器&#xff0c;该器件的操作可以在两种模式下完成&#xff0c;分别是单稳态和非稳态。CD4047需要一个外部电阻器和电容器来决定单稳态…

二叉树的前序中序后序遍历

二叉树的前序中序后序遍历-含递归和迭代代码 前序(中左右)中序(左中右)后序(左右中) 前序(中左右) 对于二叉树中的任意一个节点&#xff0c;先打印该节点&#xff0c;然后是它的左子树&#xff0c;最后右子树 A-B-D-E-C-F //递归 const preorderTraversal (root) > {const…

基于ROPNet项目训练modelnet40数据集进行3d点云的配置

项目地址&#xff1a; https://github.com/zhulf0804/ROPNet 在 MVP Registration Challenge (ICCV Workshop 2021)&#xff08;ICCV Workshop 2021&#xff09;中获得了第二名。项目可以在win10环境下运行。 论文地址&#xff1a; https://arxiv.org/abs/2107.02583 网络简介…

flask web学习之flask与http(一)

文章目录 一、请求响应循环二、HTTP请求1. 请求报文2. request对象3. 在flask中处理请求3.1 路由匹配3.2 设置监听的http方法3.3 URL处理 三、请求钩子 一、请求响应循环 每一个web应用都包含这种处理方式&#xff0c;请求-响应循环&#xff1a;客户端发出请求&#xff0c;服务…

实战经验分享,Python 连接 Oracle 踩坑实录

最近的一个测试任务需要测试 oracle 同步 hive 数据库的性能&#xff0c;那就需要对 oracle 数据库灌注测试数据。我就又打开了我的IDE&#xff0c;准备把我之前一下可以灌50w数据到 MySQL 的代码&#xff0c;改一改&#xff0c;直接用。 因为我在网上看到&#xff0c;语法上也…

基于Springboot的社区医院管理服务系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的社区医院管理服务系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

高低温交变湿热实验箱

产品概述 武汉凯迪正大高低温实验箱&#xff08;恒温恒湿试验箱&#xff09;乃针对各种材质表面处理&#xff0c;包含涂料、电镀、有机及无机皮膜&#xff0c;阳极处理&#xff0c;防锈油等防腐处理后测试其耐腐蚀性&#xff0c;从而确立产品的质量。 产品特点 1、内箱尺寸…

全网最新最全面的Appium自动化:Appium常用操作之按键类操作

按键类操作 按键类操作用来模拟在手机设备上进行按键操作&#xff08;推荐使用 方式一 &#xff09; 方式一、press_keycode(self,keycode,metastateNone,flagsNone)&#xff1a;模拟按键输入&#xff0c;其中&#xff1a; keycode&#xff1a;发送到设备的键值编码可以通过An…

华为快应用中自定义Slider效果

文章目录 一、前言二、实现代码三、参考链接 一、前言 在华为快应用中官方提供了<slider>控件&#xff0c;但是这个控件的限制比较多&#xff0c;比如滑块无法自定义&#xff0c;所以这里进行下自定义&#xff0c;自己修改样式。 二、实现代码 整体效果如下: 源码如下…

【数据结构(七)】查找算法

文章目录 查找算法介绍1. 线性查找算法2. 二分查找算法2.1. 思路分析2.2. 代码实现2.3. 功能拓展 3. 插值查找算法3.1. 前言3.2. 相关概念3.3. 实例应用 4. 斐波那契(黄金分割法)查找算法4.1. 斐波那契(黄金分割法)原理4.2. 实例应用 查找算法介绍 在 java 中&#xff0c;我们…

全面解析修复msvcr120.dll缺失问题的方法,msvcr120.dll丢失的原因

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是“msvcr120.dll丢失”。这个错误通常会导致某些程序无法正常运行&#xff0c;给用户带来很大的困扰。那么&#xff0c;当我们遇到这个问题时&#xff0c;应该如何修复呢&#xff1f;本文…