【问题标题】:Android generalized function for state flow in fragmentFragment中状态流的Android通用函数
【发布时间】:2021-03-14 16:39:18
【问题描述】:

我在我的应用程序中使用StateFlow,在我的Fragment 中使用它来-

private var job: Job? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        job = lifecycleScope.launchWhenResumed {
            viewModel.getData().collect {
                // ...
            }
        }
    }

    override fun onPause() {
        job?.cancel()
        super.onPause()
    }

如您所见,我取消了onPause 中的工作。我怎样才能使用通用函数,这样我就可以避免在每个片段中都使用job?.cancel

我不喜欢使用BaseFragment

【问题讨论】:

  • 你可以在 onPause 中使用 job?.cancel() 创建抽象类并扩展它
  • @AlexRmcf 你能给我一个例子吗
  • 不使用基础片段有什么特别的原因吗?
  • 随着应用程序的发展,随着时间的推移,基类无论如何都会被滥用
  • 你打算在fragment恢复后再次收集流量吗?在第一次暂停之前,我看不到仅用于收集的用例

标签: android kotlin kotlin-coroutines


【解决方案1】:
public class AnyOfYourFragments extends AbsractFragment{

   //you do here what you want to do
   
}

在你的 AbstractFragment 中:

public abstract class AbstractFragment extends Fragment{
private var job: Job? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        job = lifecycleScope.launchWhenResumed {
            viewModel.getData().collect {
                // ...
            }
        }
    }

    override fun onPause() {
        job?.cancel()
        super.onPause()
    }
}

我不知道 kotlin,所以我的代码有点与 java 混合,但我相信你明白了

【讨论】:

    【解决方案2】:

    一个简单的解决方案是利用片段生命周期在暂停时自动取消作业。

    fun CoroutineScope.launchUntilPaused(lifecycleOwner: LifecycleOwner, block: suspend CoroutineScope.() -> Unit){
        val job = launch(block = block)
        lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onPause(owner: LifecycleOwner) {
                job.cancel()
                lifecycleOwner.lifecycle.removeObserver(this)
            }
        })
    }
    
    //Usage
    class MyFragment: Fragment() {
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            lifecycleScope.launchUntilPaused(this){
                someFlow.collect{
                    ...
                }
            }
        }
    }
    

    如果每个片段有很多这样的作业,我建议改用自定义 CoroutineScope,以避免有许多生命周期观察者处于活动状态。

    class CancelOnPauseScope(lifecycleOwner: LifecycleOwner): CoroutineScope by MainScope(){
        init{
            lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver{
                override fun onPause(owner: LifecycleOwner) {
                    cancel()
                    lifecycleOwner.lifecycle.removeObserver(this)
                }
            })
        }
    }
    
    class MyFragment: Fragment() {
        private val scope = CancelOnPauseScope(this)
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            scope.launch{
                someFlow.collect{
                    ...
                }
            }
        }
    }
    

    【讨论】:

    • 您好,第一个实现将无法正常工作。您正在订阅收集 onViewCreated() 但停止收听 onPause()。它可能会产生一种情况,例如,当用户阻止设备然后取消阻止时,您的订阅将丢失。在 onStart() 中订阅并在 onStop 中取消可能会更好,甚至是 onResume() 和 onPause()。
    • @AndriiAfanasenko 你是绝对正确的,这就是它的工作原理。然而,问题是如何实现这种确切的行为
    【解决方案3】:

    一种新的方式:

       // Start a coroutine in the lifecycle scope
        lifecycleScope.launch {
            // repeatOnLifecycle launches the block in a new coroutine every time the
            // lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
            repeatOnLifecycle(Lifecycle.State.STARTED) {
            }
         }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 2017-08-29
      • 2016-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多