Stateflow 在 reyclerview android kotlin 中引用整个数据

2023-12-07

嘿嘿我正在学习状态流在 Android 科特林中。我正在创建一个反向对话日历视图回收者视图. In my mainactivity有一个fragment,里面有我reyclerview。我的目标是做分页的东西 in my 回收者视图所以我先加载几个月,然后在我的回收视图中添加越来越多的数据answer。我成功地实现了它。但问题是当我到达临界点并触发新数据。我的整个列表已刷新,但未更新,而是删除了以前的数据。我不明白为什么会发生这种情况可变状态流而且我也是这方面的新手flow. My Github项目链接在这里。请指导我在这里做错了什么。我的目标是预先添加 stateFlow 数据。谢谢

对话片段.kt

class ConversationFragment(val customManager: CustomManager) : Fragment() {

    companion object {
        private const val DATA = "data"
        fun create(
            data: List<ConversationDate>,
            customManager: CustomManager
        ): ConversationFragment {
            val fragment = ConversationFragment(customManager)
            val bundle = Bundle()
            bundle.putParcelableArrayList(
                DATA,
                ArrayList<Parcelable>(data)
            )
            fragment.arguments = bundle
            return fragment
        }
    }

    private var _binding: ConversationFragmentLayoutBinding? = null
    private val binding get() = _binding!!
    private val visibleThreshold = 7
    private var previousTotalItemCount = 0
    private var loading = true
    private val weeklyAdapter = ConversationWeeklyAdapter()
    private val viewModel by viewModels<FragmentViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        setupViewModel()
        _binding = ConversationFragmentLayoutBinding.inflate(inflater, container, false)
        setupView()
        return binding.root
    }

    private fun setupViewModel() {
        viewModel.data = arguments?.getParcelableArrayList(DATA)
        viewModel.startDate = customManager.startDate()
        viewModel.endDate = customManager.endDate()
    }

    private fun setupView() {
        viewModel.weeklyFormatData()

        activity?.lifecycleScope?.launchWhenCreated {
            activity?.repeatOnLifecycle(Lifecycle.State.CREATED) {
                viewModel.prepareMutableStateFlow.collectLatest {
                    weeklyAdapter.submitList(it)
                }
            }
        }

        binding.conversationView.apply {
            adapter = weeklyAdapter
            layoutManager = LinearLayoutManager(context).apply {
                orientation = LinearLayoutManager.HORIZONTAL
                stackFromEnd = true
            }

            addOnScrollListener(object : RecyclerView.OnScrollListener() {

                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                    val firstVisibleItemPosition =
                        (recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
                    val totalItemCount = recyclerView.adapter?.itemCount

                    if (totalItemCount != null) {
                        if (totalItemCount < previousTotalItemCount) {
                            previousTotalItemCount = totalItemCount
                            if (totalItemCount == 0) {
                                loading = true
                            }
                        }
                    }

                    if (totalItemCount != null) {
                        if (loading && (totalItemCount > previousTotalItemCount)) {
                            loading = false
                            previousTotalItemCount = totalItemCount
                        }
                    }

                    if (!loading && firstVisibleItemPosition < visibleThreshold) {
                        customManager.loadMoreData()
                        loading = true
                    }

                }
            })
        }

    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    fun loadMoreData(item: List<ConversationDate>) {
        viewModel.startDate =
            SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse("2021-11-01")
        viewModel.endDate =
            SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse("2021-11-30")
        val previousData = viewModel.data
        if (previousData != null) {
            viewModel.data = previousData + item
        }
        viewModel.weeklyFormatData()
    }
}

FragmentViewModel.kt

class FragmentViewModel(app: Application) : AndroidViewModel(app) {

    var data: List<ConversationDate>? = null
    var startDate: Date? = null
    var endDate: Date? = null
    private val dateRange: MutableList<Date>
        get() {
            val datesInRange = mutableListOf<Date>()
            val tempCalendar = Calendar.getInstance()
            tempCalendar.time = startDate as Date
            while (tempCalendar.time <= endDate) {
                datesInRange.add(tempCalendar.time)
                tempCalendar.add(Calendar.DATE, 1)
            }
            return datesInRange
        }
    val prepareMutableStateFlow: MutableStateFlow<List<ConversationCount>> =
        MutableStateFlow(emptyList())

    fun weeklyFormatData() {
        val conversationCount = mutableListOf<ConversationCount>()
        viewModelScope.launch {
            dateRange.forEachIndexed { index, dateRangeValue ->
                val findData = data?.find {
                    dateRangeValue == it.dateObject
                }
                conversationCount.add(
                    ConversationCount(
                        setDay(dateRangeValue),
                        index,
                        findData != null
                    )
                )
            }
            prepareMutableStateFlow.value = conversationCount
        }
    }

    private fun setDay(date: Date): String? {
        return SimpleDateFormat("dd", Locale.getDefault()).format(date)
    }
}

我的模拟 API 响应link

问题描述

加载应用程序时,将出现片段屏幕并显示一些日期。我设置开始日期 as 2021-12-01 and endDate截至今天日期,即2022-01-13。因此,当开始滚动并达到加载更多数据的阈值时。我通过了比开始日期 as 2021-11-01 and endDate as 2021-11-30。它已添加到列表中,但以前的数据已被删除。我不明白为什么会发生这种情况。我正在附上我的 YouTubelink


这是大量的代码需要完成,我无法弄清楚你想要做的一切。你没有表现出什么CustomManager.loadMoreData()做。但我假设这是一个当您滚动到底部时会加载其他项目的列表?如果您逐步了解以下逻辑onScrolled功能,好像没有什么意义。就像为什么会totalItemCount永远小于previousTotalItemCount?

如果您向下滚动到@明阮对您链接的问题的回答,这是一个更简单的解决方案。我会更进一步,创建一个辅助类,以便您可以保持片段代码干净。我添加了一项功能,当新数据到达适配器时,它会自动注册以重置自身。注意,我还没有测试过这个课程!

class BottomReachedListener(
    var onBottomReached: () -> Unit = {}
) : RecyclerView.OnScrollListener() {
    private var isTriggered = false
    private var registeredAdapter: RecyclerView.Adapter<*>? = null
    private val observer = object: RecyclerView.AdapterDataObserver() {
        override fun onChanged() = reset()
    }
    
    fun reset() {
        isTriggered = false
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        if (isTriggered) {
            return
        }
        val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
            ?: error("No LinearLayoutManager")
        val totalItems = layoutManager.itemCount
        val lastVisibleItem = layoutManager.findLastVisibleItemPosition()

        if (lastVisibleItem == totalItems - 1) {
            registerWithAdapter(recyclerView)
            isTriggered = true
            onBottomReached()
        }
    }

    private fun registerWithAdapter(recyclerView: RecyclerView) {
        registeredAdapter?.unregisterAdapterDataObserver(observer)
        registeredAdapter = recyclerView.adapter
        registeredAdapter?.registerAdapterDataObserver(observer)
    }
}

现在,在您的 Fragment 中,您需要做的就是将此类的实例设置为滚动侦听器,并向其传递一个回调,以在需要加载新数据时调用:

addOnScrollListener(BottomReachedListener {
    customManager.loadMoreData() // for example
})

不知道你的下游逻辑是否还有其他问题。如果没有实际的应用程序进行调试并了解其应该执行的所有操作,则代码太多,无法推理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Stateflow 在 reyclerview android kotlin 中引用整个数据 的相关文章

  • Android 卷页动画

    我对 Android 动画有点陌生 目前我正在开发一个故事活动 需要像 iPhone 中那样使用卷页动画 我发现 iPhone 中有一种方法可以做到这一点 但我仍然找不到在android中做的方法 所以请帮我解决这个问题 谢谢大家 谷歌代码
  • 位图背景图像应支持哪些屏幕尺寸/密度组合?

    我正在编写一个应用程序 我需要一些全屏位图背景 基于我天真的阅读支持多屏 http developer android com guide practices screens support html在 Android 文档中 为了涵盖我的
  • app-release-unsigned.apk 未签名

    我在 github 上下载了 Android 应用程序的 zip 文件 并尝试运行它 但出现一个包含此消息的对话框 app release unsigned apk is not signed Please configure the si
  • Android:如何让设备只运行一个应用程序?

    我有一个客户项目 我必须制作单任务 Android 设备 客户无法逃脱我公司开发的应用程序 此外 客户无法启动任何其他应用程序 而我们的应用程序会在设备启动时启动 总体而言 客户能够使用设备执行的所有操作就是运行我们的应用程序 除了 roo
  • 如何在 Jetpack compose 中制作 FlipCard 动画

    我有一个现有的应用程序 我在其中使用 XML 中的 Objectanimator 实现了 FlipCard 动画 如下所示 如果我点击一张卡片 它会水平翻转 但现在我想将其迁移到 jetpack compose 那么jetpack comp
  • 如何在Android中访问现有的sqlite数据库?

    到目前为止 我们已经在 Android 中开发了在运行时创建数据库的应用程序 我们想知道如何在 Android 应用程序中访问预构建或现有的数据库 sqlite 文件 请提供详细信息 查看文档android database sqlite
  • Android ViewModel LiveData 在按钮单击时更新视图

    我正在关注这个tutorial https developer android com topic libraries architecture guide html common problems faced by app develop
  • 该项目可能使用的 Gradle 版本不包含“compileSdkVersion()”方法

    当我尝试运行最初在 Eclipse ADT 上创建的项目时 我遇到了这个问题 Error 17 0 Gradle DSL method not found compileSdkVersion Possible causes ul li Th
  • 合并 dex 程序类型已存在时出错:android.support.v4.os.ResultReceiver$MyResultReceiver

    合并dex时出错 以下是依赖项 ext anko version 0 10 5 support lib 1 0 0 alpha1 room lib 1 1 0 dependencies implementation org jetbrain
  • java.net.ProtocolException:流意外结束

    我面临一个奇怪的问题 并且无法调试它 我已经实现了上传数据流的逻辑 并使用 Volley 来实现相同的功能 我在HurlStack addBodyIfExistsapi 以便可以处理 application octet stream 类型的
  • 垂直从上到下线手势检测器

    我用的是 手势工具 注意到对于垂直从上到下的线无法检测 因为我在代码中使用生成的手势文件 如下所示 但无法检测垂直从上到下的线手势检测 import java util ArrayList import android app Activi
  • Android 媒体播放器搜索栏

    我有一个创建 播放和处理媒体播放器 只是音频 的服务 但我在主要活动中有一个搜索栏 我想自然地显示音频文件的进度并允许用户搜索到不同的位置 我花了很长时间才弄清楚 将 UI 中的搜索栏连接到服务中的媒体播放器的最佳或正确方法是什么 我将这样
  • 从 Android 访问云存储

    我一直无法找到任何有关如何从 Android 应用程序使用云存储的具体文档 我确实遇到过这个客户端库 https cloud google com storage docs reference libraries然而 Google Clou
  • Android 解析 JSON 卡在 get 任务上

    我正在尝试解析一些 JSON 数据 我的代码工作了一段时间 我不确定我改变了什么突然破坏了代码 当我运行代码时 我没有收到任何运行时错误或警告 我创建一个新的 AsyncTask 并执行它 当我打电话时 get 在这个新任务中 调试器在此行
  • 分离 Fragment 和删除 Fragment 有什么区别?

    在 Android 文档中碎片交易 http developer android com reference android app FragmentTransaction html我注意到两种非常相似的方法 detach and remo
  • 推特更新状态

    我正在通过 twitter4j 将 Twitter 集成到 Android 我可以成功阅读我发布的推文 现在我试图用它发布推文 但我不能 我收到如下奇怪的警告 02 01 16 28 43 298 WARN System err 729 4
  • 可用屏幕的尺寸

    我使用的是 Nexus 7 1280x800 android 4 2 2 API 17 我想获取屏幕的大小 将其划分为相同高度和宽度的正方形部分 我正在使用 FrameLayout 我的方块是 ImageView 的子类 我这样做 cont
  • Android Studio 中自动打开“运行设备”选项卡

    在 Android Studio Flamingo 中有一个名为跑步设备并且它会在每次之后自动打开运行应用程序 有办法禁止这个自动打开吗 我尝试禁用启用物理 Android 设备的镜像选项 但选项卡仍然自动打开 基于此issue https
  • Android Volley - 发布请求 - 无法在线工作

    我试图通过 Volley 发出 POST 请求 它在我的本地主机中工作得很好 但是当我将它移动到网络服务器时 响应为空 Java代码 RequestQueue queue Volley newRequestQueue this String
  • 如何减少 Android 中浮动 editText 提示和 editText 框之间的空间?

    我有一个带有浮动提示的 EditText 但我想知道如何减少浮动提示和 EditText 框之间的空间 现在我的用户界面看起来像https i stack imgur com ltfra jpg https i stack imgur co

随机推荐

  • cherry-pick 命令是否会生成同一提交的不同哈希码?

    我对樱桃采摘不太了解 只需要清除cherry pick命令在不同分支中生成相同提交的不同哈希代码 实际上 我正在挑选不同分支中的哈希码 在这里我注意到它正在生成现有提交的不同哈希代码 是它的工作流程还是这里存在任何问题 提交哈希不仅基于提交
  • 变量不会在颤动中动态更改文本

    我已经定义了我的应用程序 并且通过了counter变量作为构造函数 如下所示 class AppThreePlusThree extends StatelessWidget override Widget build BuildContex
  • 用PHP将EXIF写入JPG

    几天来 我尝试使用 PHP 在 JPG 图像中写入 或更新 EXIF 信息 地理标记 纬度和经度 在咨询了很多网站但没有成功之后 我认为最好的选择是使用Imagick 但是虽然我似乎可以使用setImageProperty 设置纬度和经度
  • rand() 返回相同的数字[重复]

    这个问题在这里已经有答案了 我正在使用 rand 在 C 中制作一个简单的示例 但尽管我使用 srand 但该函数始终返回相同的数字 这是代码 include
  • Angular:为组件字段提供对服务功能的引用并从模板调用它,但未按预期工作

    在我的 Plunker 里 修改的英雄之旅来自官方文档的应用程序 我在hero service doHeroesExist boolean console log doHeroesExist called this heroesExist
  • 如何使用 PHP 或 Ruby 从图像中删除某些颜色?

    假设有 3 个圆圈 红 蓝 黑 我只希望保留黑色圆圈 如何去除红色和蓝色圆圈 既然您要求 PHP 解决方案 首先加载你的图片图像从png创建或其他图像格式的类似功能 然后 使用imagesx and imagesy来获取图像的大小 现在 您
  • 如何使用CSS将子div居中对齐父div内?

    我是 html 和 css 新手 我不知道如何在父 div 内居中对齐子 div 这是我的代码 请回答并解决我的问题 CSS page position relative width 1220px height 670px backgrou
  • Flutter apk已安装但无法找到/打开

    我花了几周的时间试图解决这个问题 但我无法让它发挥作用 Context 颤振运行 我可以执行 flutter run 它将在我的手机上启动该应用程序 关闭应用程序后 我在应用程序页面中看不到它 我无法搜索它 访问 应用程序的唯一方法是转到设
  • 你能在 kivy 文件中换行吗?

    我的 kv 中有几行 文件非常长 80多个字符 我想知道是否有办法在下一行包装 继续它们 例如 我该如何从这个 Line points self pos 0 5 self pos 1 2 self pos 0 self width 5 se
  • Win32 - 从 C 代码回溯

    我目前正在寻找一种在 Windows 下从 C 代码 非 C 获取回溯信息的方法 我正在构建一个跨平台 C 库 具有引用计数内存管理功能 它还具有集成的内存调试器 可提供有关内存错误的信息 XEOS C 基础库 当发生故障时 启动调试器 提
  • Oracle JSON_OBJECT NULL ON NULL 子句不起作用

    我正在尝试让 Oracle 生成 JSONnullSQL 上的值NULL数据 如下 select json object key a value 1 key b value null null on null c1 json object
  • 在 mocha 中测试 NodeJS 时,域无法正确捕获错误

    当运行利用域进行错误处理的测试时 即使库内的域处理程序应该捕获错误 Mocha 仍然会抛出错误 如果我在 Mocha 之外执行代码 它会正常运行 让我相信问题出在 Mocha 上 Example foo js module exports
  • Java 中删除字符串中的空格

    我有一个像这样的字符串 mysz name john age 13 year 2001 我想删除字符串中的空格 我试过trim 但这只会删除整个字符串前后的空格 我也尝试过replaceAll W 但随后 也会被删除 我怎样才能获得一个字符
  • 如何在ajax响应中从字节流渲染pdf

    我正在开发一个移动应用程序 我们正在使用 jquery mobile 我们可以选择查看或下载 pdf 格式的记录 我无法控制后端 我将在 json 对象中获取 pdf 数据作为 ajax 响应 我想读取该数据并以 pdf 形式显示 我的下一
  • 共享 SD 卡中的图像

    我花了两周时间寻找如何共享存储在 SD 卡上的图像 但没有成功 This answer对我不起作用 也不是我正在寻找的 我正在与凸轮预览应用程序将图像存储到 SD 然后在应用程序内图库中显示它们 public class GalleryVi
  • 特定存储库的 Git 全局配置?

    意思是 有类似每个回购部分的东西 repo url 覆盖全局 不适用于特定存储库 选项 core filemode false editor notepad repo example com repo1 git core filemode
  • R 中的“错误恢复文件幻数”错误

    As in 加载 R 工作区时什么可能导致 错误的幻数 错误以及如何避免它 and R 有幻数 PNG 错误 我得到一个错误恢复文件幻数 error gt load fossilien dat Error bad restore file
  • 沙盒阻止我格式化字符串

    我有一个简单的常规脚本 node master echo I am about to try to use String format def jjj String format bob echo jjj 如果我将此脚本直接放入我的作业配置
  • GridLayout 未填充 JPanel

    我遇到 GridLayout 问题 并且整个 JPanel 未填充 我有一个 N M 网格 我用 N M 瓷砖填充它 它们扩展了 JPanel 添加所有这些图块后 JPanel 的底部和右侧仍然有空间 我认为 GridLayout 应该填满
  • Stateflow 在 reyclerview android kotlin 中引用整个数据

    嘿嘿我正在学习状态流在 Android 科特林中 我正在创建一个反向对话日历视图回收者视图 In my mainactivity有一个fragment 里面有我reyclerview 我的目标是做分页的东西 in my 回收者视图所以我先加