KunMinX / MVI-Dispatcher-KTX

简明易用框架,解决 MVI 实战痛点
Apache License 2.0
162 stars 12 forks source link

onCreate 时发送的Intent 事件在 App 从后台返回的时候被异常消费了 #6

Open zicen opened 7 months ago

zicen commented 7 months ago

代码修改截图: image 就是新增了一个测试事件在 onCreate 生命周期的时候调用 日志截图: img_v3_0277_8a9b23b0-3aaa-4dd8-9195-7ea66197eddg APP 在前台的时候没响应 onCreate 发的事件是符合预期的,因为事件的收集是在 onStart 阶段,但是此时退到后台再返回,情况就不对了,这时候把 onCreate 发的事件响应了。

zicen commented 7 months ago

操作视频:

https://github.com/KunMinX/MVI-Dispatcher-KTX/assets/18431596/17762295-a557-40f2-926d-cd731bf2f354

zicen commented 7 months ago

晚上在 MviDispatcher 内打印了一些日志:

protected suspend fun sendResult(intent: T) {
    version++
    Log.d("MviDispatcherKTX", "sendResult version:$version currentVersion:$currentVersion consumer:$intent")
      _sharedFlow.emit(ConsumeOnceValue(value = intent))
  }
private fun outputTo(lifecycleOwner: LifecycleOwner?, observer: (T) -> Unit) {
    currentVersion = version
    observerCount++
    lifecycleOwner?.lifecycle?.addObserver(this)
    lifecycleOwner?.lifecycleScope?.launch {
      lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        _sharedFlow.collect {
          Log.d("MviDispatcherKTX", "_sharedFlow.collect version:$version currentVersion:$currentVersion isAllConsumed:${it.isAllConsumed} consumer:$it")
          if (version > currentVersion) {
            if (it.isAllConsumed) return@collect
            ++it.consumeCount
            observer(it.value)
            if (it.consumeCount == observerCount) it.isAllConsumed = true
          }
        }
      }
    }
  }

打印出的日志如下:

// 进入页面
2024-01-18 21:54:03.897  8725-8725  ListFragment            com.kunminx.purenote_ktx             D  input NoteIntent.TestCreateMsg:1
2024-01-18 21:54:03.897  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  sendResult version:0 currentVersion:-1 consumer:com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635
2024-01-18 21:54:03.897  8725-8725  ListFragment            com.kunminx.purenote_ktx             D  input NoteIntent.TestCreateMsg:2
2024-01-18 21:54:03.897  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  sendResult version:1 currentVersion:-1 consumer:com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635
2024-01-18 21:54:03.982  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:1 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=0, isAllConsumed=false, value=com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635)
2024-01-18 21:54:03.983  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:1 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=0, isAllConsumed=false, value=com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635)
// 请求接口  此时将 version 变更为2 currentVersion 为1 也即此时消息变为可用的了
2024-01-18 21:54:04.037  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  sendResult version:2 currentVersion:1 consumer:GetNoteList(notes=[Note(id=551b8d57-1cef-4752-8bd2-ac849b440a51, title=hdhdhdhejjeje, content=orikfjfjfjfn, createTime=1704288384456, modifyTime=1704355889918, type=2), Note(id=9ce07f7f-4cf2-408f-8c2c-c11a8556d919, title=hahaha, content=jdjdjjejrjr, createTime=1704288376241, modifyTime=1704288412812, type=0), Note(id=2c92b67f-235b-4dec-9526-d8cb42491ccc, title=, content=, createTime=1704288400123, modifyTime=1704288400123, type=0)])
2024-01-18 21:54:04.037  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:2 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=0, isAllConsumed=false, value=GetNoteList(notes=[Note(id=551b8d57-1cef-4752-8bd2-ac849b440a51, title=hdhdhdhejjeje, content=orikfjfjfjfn, createTime=1704288384456, modifyTime=1704355889918, type=2), Note(id=9ce07f7f-4cf2-408f-8c2c-c11a8556d919, title=hahaha, content=jdjdjjejrjr, createTime=1704288376241, modifyTime=1704288412812, type=0), Note(id=2c92b67f-235b-4dec-9526-d8cb42491ccc, title=, content=, createTime=1704288400123, modifyTime=1704288400123, type=0)]))
// 退到后台返回 粘性一般恢复了所有历史消息
2024-01-18 21:55:32.058  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:2 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=0, isAllConsumed=false, value=com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635)
2024-01-18 21:55:32.058  8725-8725  ListFragment            com.kunminx.purenote_ktx             D  output NoteIntent.TestCreateMsg:com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635
2024-01-18 21:55:32.058  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:2 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=0, isAllConsumed=false, value=com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635)
2024-01-18 21:55:32.058  8725-8725  ListFragment            com.kunminx.purenote_ktx             D  output NoteIntent.TestCreateMsg:com.kunminx.purenote.domain.intent.NoteIntent$TestCreateMsg@7db9635
2024-01-18 21:55:32.058  8725-8725  MviDispatcherKTX        com.kunminx.purenote_ktx             D  _sharedFlow.collect version:2 currentVersion:1 consumer:ConsumeOnceValue(consumeCount=1, isAllConsumed=true, value=GetNoteList(notes=[Note(id=551b8d57-1cef-4752-8bd2-ac849b440a51, title=hdhdhdhejjeje, content=orikfjfjfjfn, createTime=1704288384456, modifyTime=1704355889918, type=2), Note(id=9ce07f7f-4cf2-408f-8c2c-c11a8556d919, title=hahaha, content=jdjdjjejrjr, createTime=1704288376241, modifyTime=1704288412812, type=0), Note(id=2c92b67f-235b-4dec-9526-d8cb42491ccc, title=, content=, createTime=1704288400123, modifyTime=1704288400123, type=0)]))

可以基本推断出是由于这行代码引起: image 注释掉之后正常。说明确实存在这种极限case缺陷。

KunMinX commented 7 months ago

感谢你的反馈。根据你提供的信息,个人认为问题是由于 input 发生在 requester 被注册前所致。

fragment 的 view 无法在 onCreate 阶段直接获得,导致 fragment 基类的 onOutput 抽象方法的执行位置无法和 activity 一样,按一定顺序统一放在基类的 onCreate 方法中。目前 fragment 基类中的 onOutput 抽象方法是置于 onViewCreated 方法中,当人们误在 fragment 子类的 onCreate 中 input 数据,就会造成上述现象。

目前暂未找到更好的办法,只能是开发者自己注意,避免在 onOutput 注册前,发生 input。 如有自己验证过可行的变通方案,欢迎分享。