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 Studio 3.0 Canary 9 - 无法解析包

    我在 Android Studio 3 0 Canary 9 中遇到几个错误 这些错误是 无法解析 android 软件包 下面列出了一些错误 我刚刚安装了 SDK 的所有额外软件包 但仍然收到 gradle 构建错误 Error 82 1
  • 在 Android Studio 中,为什么我必须在模拟器中单击“运行应用程序”两次才能启动应用程序?

    在 Android Studio 中 当我按播放按钮在 Android 模拟器上安装并运行应用程序时 大约 5 10 秒后 我在屏幕底部收到一条消息 显示 安装成功 但应用程序实际上并未运行在模拟器上 我必须再次按下播放按钮 这是非常令人沮
  • Android - 从资产中解析巨大(超大)JSON 文件的最佳方法

    我正在尝试从资产文件夹中解析一些巨大的 JSON 文件 我如何加载并添加到 RecyclerView 我想知道解析这种大文件 大约 6MB 的最佳方法是什么 以及您是否知道可以帮助我处理此文件的良好 API 我建议您使用GSON lib h
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序
  • SearchView过滤ListView

    我已经实现了搜索视图来过滤我的列表视图项目 当我输入任何文本时 它会过滤列表 但当我退出搜索视图时 它不会返回原始列表项 public class PlacesListAdapter extends ArrayAdapter
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • android xamarin 中的 reCaptcha

    我想在 Xamarin android 应用程序中实现验证码 我抓住了这个在 Android 中集成 googles reCaptcha 验证 https www c sharpcorner com article how to integ
  • Android Activity 生命周期函数基础知识

    我正在测试这段代码 它显示活动所处的状态 public class Activity101Activity extends Activity String tag Lifecycle Called when the activity is
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Android 中 Kotlin 协程的正确使用方式

    我正在尝试使用异步更新适配器内的列表 我可以看到有太多的样板 这是使用 Kotlin 协程的正确方法吗 这个可以进一步优化吗 fun loadListOfMediaInAsync async CommonPool try Long runn
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • 错误:在根项目“projectName”中找不到项目“app”

    我有一个在 Eclipse 中开发的旧应用程序 现在尝试将其迁移到 Android Studio 我更新了库并遵循了基本步骤 现在 我收到此错误 Error Project app not found in root project pro
  • 增加活动的屏幕亮度

    显然 Android 操作系统中至少有三种不同的技术可以改变屏幕亮度 其中两个在纸杯蛋糕之后不再起作用 而第三个被接受的技术显然有一个错误 我想在单视图活动开始时增加屏幕亮度 然后在活动结束时将亮度恢复为用户设置 没有按钮 没有第二个视图或
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时

随机推荐

  • 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 回收者视图所以我先加