android - 如何使用协程连续执行操作?
问题描述
我知道在单个协程范围内,其中的所有操作都是按顺序执行的。但是为什么它不能以这种方式工作以及如何使其工作。预期的结果是我多次单击该按钮,它会一一处理我的所有点击,因此第 10 个 Hello World 必须在 10 秒内登录。但实际上我所有的点击都是异步工作的,第 10 次 Hello World 登录约 2 秒
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!"
}
}
解决方案
您可以使用 Channel 并使用其缓冲容量,如下所示:
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
适当地取消即可。
推荐阅读
- java - 您好我正在尝试将 json 数据从 url 显示到 listview 中。虽然什么都没有显示
- fortran - 跨系统的不同本机字符集 - ICHAR
- splunk - Splunk 存储桶名称转换为纪元到人类脚本
- php - 如何在不破坏单元测试的情况下查看 PHP 内部服务器启动的所有输出?
- javascript - 为什么使用 ldapjs 我无法连接到我的服务器?
- nginx - Ingress nginx 仅在特定主机上启用 Cors 标头
- javascript - Typescript 闭包评估,“this”
- javascript - TypeError: getPlugin(...).createPeerConnection 不是新 RTCPeerConnection 的函数
- javascript - Angular - 如何将 Javascript 导入 Angular 组件
- c# - 如何使用 C# 通过 Click To Run 或 MSI 检测 Office 安装