我知道在一个协程范围内,它内部的所有操作都是顺序执行的。但是为什么它不能以这种方式工作以及如何使其工作。 预期的结果是我多次单击该按钮,并且它一次又一次地处理了所有单击,因此第十个Hello World必须在10秒内登录。但实际上,我的所有点击都是异步运行的,并且在登录〜2秒后登录了第十个Hello World
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coroutineScope = CoroutineScope(Dispatchers.IO)
btn.setOnClickListener {
coroutineScope.launch {
Log.d("myTag",hello())
}
}
}
suspend fun hello(): String {
delay(1000)
return "Hello, World!"
}
}
答案 0 :(得分:2)
您可以使用一个频道来播放其缓冲容量,如下所示:
class MainActivity : AppCompatActivity() {
val channel = Channel<Unit>(10) //Supports up to 10 clicks unattended
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coroutineScope = CoroutineScope(Dispatchers.IO)
btn.setOnClickListener {
coroutineScope.launch {
channel.send(Unit)
}
}
coroutineScope.launch {
for(i in channel) {
Log.d("myTag",hello())
}
}
}
suspend fun hello(): String {
delay(1000)
return "Hello, World!"
}
}
或者,如果您愿意,也可以将点击作为流消耗,如下所示:
class MainActivity : AppCompatActivity() {
val channel = Channel<Unit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coroutineScope = CoroutineScope(Dispatchers.IO)
btn.setOnClickListener {
coroutineScope.launch {
channel.send(Unit)
}
}
val clicksFlow = channel.consumeAsFlow()
coroutineScope.launch {
clicksFlow
.buffer(Channel.BUFFERED) //Supports up to 64 clicks unattended
.collect {
Log.d("myTag",hello())
}
}
}
suspend fun hello(): String {
delay(1000)
return "Hello, World!"
}
}
只需确保关闭channel
并适当取消coroutineScope
。
更新
您可以使用callbackFlow
(例如,建议使用@MarkoTopolnik),
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coroutineScope = CoroutineScope(Dispatchers.IO)
val clicksFlow = callbackFlow<Unit> {
btn.setOnClickListener {
offer(Unit)
}
awaitClose {
cancel()
}
}
coroutineScope.launch {
clicksFlow
.buffer(Channel.BUFFERED) //Supports up to 64 clicks unattended
.collect {
Log.d("myTag",hello())
}
}
}
suspend fun hello(): String {
delay(1000)
return "Hello, World!"
}
}
现在,您只需要确保适当取消coroutineScope
。
答案 1 :(得分:0)
Channels
是实现此目标的好方法,但是您也可以创建自己的CoroutineDispatcher
,例如
val coroutineScope = CoroutineScope(Executors.newSingleThreadExecutor().asCoroutineDispatcher())
btn.setOnClickListener {
coroutineScope.launch {
channel.send(Unit)
}
}