使用协程通道轮询存储库

时间:2019-04-20 17:35:21

标签: kotlin kotlin-coroutines

我正在使用协程频道,我想实施一个轮询测试项目。这个想法是,视图模型将侦听来自反复轮询端点的存储库中的数据。

当我将coroutineScope传递到存储库时,轮询将起作用,但是,当我在存储库中创建新的coroutineSCope时,我看到的是数据已注入到通道中,但在视图模型中没有收到。

这可行:

class PollingViewModel : ViewModel() {

    val counter = MutableLiveData<String>().apply { value = "uninitialized" }

    private val repository = Repository()

    init {
        viewModelScope.launch {
            val channel = repository.poll(this /* scope */)
            channel.consumeEach {
                Log.d("foo", "Viewmodel received [$it]")
                counter.postValue(it.toString())
            }
        }
    }
}

class Repository {

    private var startValue = 0

    suspend fun poll(coroutineScope: CoroutineScope) =
        coroutineScope.produce(capacity = Channel.CONFLATED) {
            while (true) {
                Log.d("foo", "Sending value [$startValue]")
                send(startValue++)
                delay(POLLING_PERIOD_MILLIS)
            }
        }

    companion object {
        private const val POLLING_PERIOD_MILLIS = 1000L
    }
}

但这不会(viewmodel不接收任何内容):

class PollingViewModel : ViewModel() {

    val counter = MutableLiveData<String>().apply { value = "uninitialized" }

    private val repository = Repository()

    init {
        viewModelScope.launch {
            repository.poll().consumeEach {
                Log.d("foo", "Viewmodel received [$it]")
                counter.postValue(it.toString())
            }
        }
    }
}

class Repository {

    private var startValue = 0

    suspend fun poll() = coroutineScope {
        produce(capacity = Channel.CONFLATED) {
            while (true) {
                Log.d("foo", "Sending value [$startValue]")
                send(startValue++)
                delay(POLLING_PERIOD_MILLIS)
            }
        }
    }

    companion object {
        private const val POLLING_PERIOD_MILLIS = 1000L
    }
}

在存储库级别创建coroutineScope有什么问题?

1 个答案:

答案 0 :(得分:0)

解决方案似乎是在存储库中创建一个新的CoroutineContext:

class Repository {

    private var startValue = 0
    private val context: CoroutineContext by lazy(LazyThreadSafetyMode.NONE) {
        Job() + Dispatchers.IO
    }

    suspend fun poll(): ReceiveChannel<Int> = coroutineScope {
        produce(
            context = context,
            capacity = Channel.CONFLATED
        ) {
            while (true) {
                send(startValue++)
                delay(POLLING_PERIOD_MILLIS)
            }
        }
    }

    companion object {
        private const val POLLING_PERIOD_MILLIS = 1000L
    }
}