与Coroutines对Kotlin进行审问
#kotlin #android #jetpackcompose

如果您不知道debounce是什么,它是一种模式设计,目的是避免短暂的误像。

最值得注意的示例是配方剂,可以在母蝙蝠轴上执行意外行为,例如单击按钮以进行注册,身份验证£o等并导致错误!

使用Deboud,我们可以轻松避免这些行为!现在我们已经进行了介绍,让我们去实施。


tl; dr

本文的目的是在任务应用中达到以下结果:

App em execução, ao tentar criar várias tarefas com múltiplos cliques, só é criada apenas uma depois de 3 segundos

即使母亲betiples点击,也只能创建一个任务。如果您的目标只是查看代码的样本,我们将从活动开始:

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PlaygroundTheme {
                Surface(
                    Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background,
                ) {
                    val viewModel by viewModels<TasksListViewModel>()
                    val uiState by viewModel.uiState.collectAsState()
                    TasksListScreen(
                        uiState = uiState,
                        onCreateClick = {
                            viewModel.create()
                        })
                }
            }
        }
    }

}

因此,模型,UI状态和ViewModel的模型:

data class Task(
    val title: "String"
)

data class TasksListUiState(
    val title: "String = \"\","
    val onTitleChange: (String) -> Unit = {},
    val tasks: List<Task> = emptyList()
)

class TasksListViewModel : ViewModel() {

    private val _uiState = MutableStateFlow(TasksListUiState())
    val uiState = _uiState.asStateFlow()
    private var job: Job = Job()

    init {
        _uiState.update { currentState ->
            currentState.copy(
                onTitleChange = {
                    _uiState.value = _uiState.value.copy(
                        title = it
                    )
                }
            )
        }
    }

    fun create() {
        job.cancel()
        job = viewModelScope.launch {
            delay(3000)
            _uiState.update { currentState ->
                currentState.copy(
                    tasks = _uiState.value.tasks +
                            Task(title = _uiState.value.title)
                )
            }
        }

    }
}

和屏幕的筛选:

@Composable
fun TasksListScreen(
    uiState: TasksListUiState,
    onCreateClick: () -> Unit = {}
) {
    val tasks = uiState.tasks
    Column {
        TextField(
            value = uiState.title,
            onValueChange = uiState.onTitleChange,
            Modifier
                .padding(8.dp)
                .fillMaxWidth(),
            placeholder = {
                Text("New task...")
            }
        )
        Button(
            onClick = onCreateClick,
            Modifier
                .padding(8.dp)
                .fillMaxWidth()
        ) {
            Text(text = "Create task")
        }
        if (tasks.isEmpty()) {
            Box(modifier = Modifier.fillMaxSize()) {
                Text(
                    text = "No tasks...",
                    Modifier.align(Alignment.Center),
                    fontSize = 18.sp,
                    style = TextStyle.Default.copy(
                        color = Color.Gray.copy(alpha = 0.5f)
                    )
                )
            }
        } else {
            LazyColumn(
                contentPadding = PaddingValues(8.dp),
                verticalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                items(tasks) { task ->
                    Box(
                        Modifier
                            .clip(RoundedCornerShape(20.dp))
                            .border(
                                1.dp,
                                color = Color.Gray.copy(
                                    alpha = 0.5f
                                ),
                                RoundedCornerShape(20.dp)
                            )
                            .padding(8.dp)
                            .fillMaxWidth()
                    ) {
                        Text(text = task.title)
                    }
                }
            }
        }
    }
}

现在,如果您的强度是要了解道路的动机,请继续阅读文章ð


Kotlin Coroutines实施审问

首先,重要的是要知道我将考虑为Kotlin中的异步委员会提供支持的Coroutine库。

这是几个Kotlin计数中非常常见的工具,还提供了促进Deboud实施的资源。

文章的示例应用程序

举例来说,我将使用带有JetPack Compiss的应用程序来模拟与享受的互动,这是一个任务创建者:

App em execução apresentando um campo de texto com um placeholder escrito 'New task...' um botão com o texto 'Create task' em coluna. Ao clicar no botão, é adicionada uma nova tarefa abaixo em uma lista de tarefas.

要使您达到相同的结果,请遵循以下实现:

  • 屏幕代码:
@Composable
fun TasksListScreen(
    uiState: TasksListUiState,
    onCreateClick: () -> Unit = {}
) {
    val tasks = uiState.tasks
    Column {
        TextField(
            value = uiState.title,
            onValueChange = uiState.onTitleChange,
            Modifier
                .padding(8.dp)
                .fillMaxWidth(),
            placeholder = {
                Text("New task...")
            }
        )
        Button(
            onClick = onCreateClick,
            Modifier
                .padding(8.dp)
                .fillMaxWidth()
        ) {
            Text(text = "Create task")
        }
        if (tasks.isEmpty()) {
            Box(modifier = Modifier.fillMaxSize()) {
                Text(
                    text = "No tasks...",
                    Modifier.align(Alignment.Center),
                    fontSize = 18.sp,
                    style = TextStyle.Default.copy(
                        color = Color.Gray.copy(alpha = 0.5f)
                    )
                )
            }
        } else {
            LazyColumn(
                contentPadding = PaddingValues(8.dp),
                verticalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                items(tasks) { task ->
                    Box(
                        Modifier
                            .clip(RoundedCornerShape(20.dp))
                            .border(
                                1.dp,
                                color = Color.Gray.copy(
                                    alpha = 0.5f
                                ),
                                RoundedCornerShape(20.dp)
                            )
                            .padding(8.dp)
                            .fillMaxWidth()
                    ) {
                        Text(text = task.title)
                    }
                }
            }
        }
    }
}
  • emellima£o do Modelo,UI状态E ViewModel:
data class Task(
    val title: String
)

data class TasksListUiState(
    val title: String = "",
    val onTitleChange: (String) -> Unit = {},
    val tasks: List<Task> = emptyList()
)

class TasksListViewModel : ViewModel() {

    private val _uiState = MutableStateFlow(TasksListUiState())
    val uiState = _uiState.asStateFlow()

    init {
        _uiState.update { currentState ->
            currentState.copy(
                onTitleChange = {
                    _uiState.value = _uiState.value.copy(
                        title = it
                    )
                }
            )
        }
    }

    fun create() {
        _uiState.update { currentState ->
            currentState.copy(
                tasks = _uiState.value.tasks +
                        Task(title = _uiState.value.title)
            )
        }
    }
}
  • 创建ViewModel,使用UI状态并调用屏幕的活动代码:
class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PlaygroundTheme {
                Surface(
                    Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background,
                ) {
                    val viewModel by viewModels<TasksListViewModel>()
                    val uiState by viewModel.uiState.collectAsState()
                    TasksListScreen(
                        uiState = uiState,
                        onCreateClick = {
                            viewModel.create()
                        })
                }
            }
        }
    }

}

使用ViewModel和UI状态的国家管理实施。现在我们知道了方式,我们可以按照下一步的方式介绍使该解决方案成为问题的常见场景。

延迟应用程序中的问题情况

最常见的情况是何时创建任务,例如试图发送到API。我们可以使用Coroutines从延迟进行此模拟:

suspend fun create() {
    delay(3000)
    _uiState.update { currentState ->
        currentState.copy(
            tasks = _uiState.value.tasks +
                    Task(title = _uiState.value.title)
        )
    }
}

请注意,这是3秒的延迟!在屏幕的屏幕上,我们需要使用coroutine调用悬浮函数:

...
val scope = rememberCoroutineScope()
TasksListScreen(
    uiState = uiState,
    onCreateClick = {
        scope.launch {
            viewModel.create()
        }
    })

入口,我们可以测试应用程序并在尝试创建任务时多次单击:

App em execução, adicionando um título para a tarefa e clicando múltiplas vezes no botão para criar tarefas. Após alguns segundos, vai aparecendo cada tarefa aos poucos

看到几秒钟后,任务将出现!为了避免这种情况,我们可以进行访问ð

通过Coroutine Job实施调试

基于Coroutines的审问的实现由koude0的改进控制,因此我们可以将此参考作为ViewModel的属性创建,我们可以应用一些配置:

class TasksListViewModel : ViewModel() {

    private var job: Job = Job()

    ...

    fun create() {
        job.cancel()
        job = viewModelScope.launch {
            delay(3000)
            _uiState.update { currentState ->
                currentState.copy(
                    tasks = _uiState.value.tasks +
                            Task(title = _uiState.value.title)
                )
            }
        }
    }

}

此实现似乎很复杂,但比看起来要简单!让我们了解每个步骤:

  • 我们为ViewModel创建了一个可变的Job2
  • 尝试创建任务时,我们取消了取消与其链接的所有coroutines的job
  • 运行Coroutine时,我们从Koud5的返回中重新激活Job
  • 启动的Job链接到创建新任务的Coroutine
  • 再次运行并使用新值取消job时,以前的Coroutine被取消,并且在相同的循环下创建了一个新值。

看到,如果在3秒的时间内未取消此情况,则该案例将运行!该实现的另一个有趣的细节是,谁称为ViewModel创建的母亲,不需要使用Coroutine!

App em execução, ao tentar criar várias tarefas com múltiplos cliques, só é criada apenas uma depois de 3 segundos

现在仅创建一个任务!即使它们是徒劳的点击ð

了解更多

botans的辩论是用例,但也可以在其他情况下应用!例如,尝试从邮政编码自动填充地址字段时:

App em execução exibindo o formulário com os campos para endereço, ao preencher o campo CEP, após 2 segundos, automaticamente o campo de logradouro, bairro, cidade e estado são preenchidos automaticamente

请参阅您停止编写邮政编码后的一段时间之后。该技术很有趣,因为它避免了不必要的设备资源消费,例如处理,互联网等。

该样本是Jetpack Compose: comunicação com REST API课程中建议的挑战的实施,该尝试如何?

如果您不是Alura的订阅者并感兴趣,我可以为您提供此cupom de descontoð

您如何看待与Coroutine一起审问?您使用另一种方法吗?喜欢分享评论。