Read more" />

πŸ”’ Avoiding Duplicate Calls with Kotlin Coroutines πŸ”’

πŸš€ When building an app that involves network operations, such as transferring funds, it’s crucial to prevent the user from triggering the same operation multiple times unintentionally. This could lead to duplicate transactions or other unwanted effects. Here’s a straightforward strategy using Kotlin Coroutines within a ViewModel to ensure that the transfer operation can only be executed once at a time.

Key Approach:

  • πŸ”‘ Job Control: Utilize a nullable Job variable to keep track of the ongoing transfer task. By setting this variable, you can easily check whether a previous task is still running.

Implementation Steps:

  • Handle Results: Upon completion or failure, update the UI state with the results or error message, then reset makeTransferJob to null to allow new operations. βœ…
  • Initialize a Job Variable: Create a nullable Job variable, makeTransferJob, which will control the execution flow. πŸ”„
  • Check Job Status: Before launching the coroutine for a new transfer, check if makeTransferJob is null. If not, it means a transfer is already in progress, and the function will return early. ⏱️
  • Execute Transfer: Launch a coroutine in viewModelScope to perform the transfer. Update the UI state to indicate loading at the start. πŸ”„
class MakeTransferViewModel(
    private val transfersRepository: TransfersRepository
) : ViewModel() {

    private val _uiState = MutableStateFlow<MakeTransferUiState>(...)
    val uiState: StateFlow<MakeTransferUiState> = _uiState.asStateFlow()

    private var makeTransferJob: Job? = null

    fun tryTransfer() {
        if (makeTransferJob != null) return

        makeTransferJob = viewModelScope.launch {
            try {
                _uiState.update { it.copy(isLoading = true) }
                val isTransferSuccessful = transfersRepository.makeTransfer(...)

                _uiState.update {
                    it.copy(
                        isLoading = false,
                        transferResult = TransferResult(it.transferInfo, isTransferSuccessful)
                    )
                }
            } catch (ioe: IOException) {
                _uiState.update {
                    it.copy(isLoading = false, error = ioe.message ?: "Error doing transfer")
                }
            } finally {
                makeTransferJob = null
            }
        }
    }
}

Call today

+34 634 548 126

You've found the person you were looking for. Let's talk.

Let's get you started