Search code examples
androidkotlin-coroutinesandroid-camerax

executing code in viewModelScope.launch crashes the application


I am trying to implement a timer for a CameraX video recording app, such as, the timer should update the TextView every second while recording the video. Following are the two start and stop methods that are being called from activity inside a viewModel:

fun startTimer(timerText: TextView) {
        timer = Timer()
        viewModelScope.launch(Dispatchers.IO) {
            timer?.scheduleAtFixedRate(timerTask {
                timeCount += 1u
                val tempTimerText = (timeCount / 60u).toString().padStart(2, '0') + ":" +
                        (timeCount % 60u).toString().padStart(2, '0')
                timerText.text = tempTimerText
            }, 1000, 1000)
        }

    }

    fun stopTimer(timerText: TextView) {
        if (timer != null) {
            timer?.cancel()
            timer?.purge()
            timerText.text = application.getString(R.string.video_timer)
        }
    }

Every time I call this method, the app crashes. What am I doing wrong? How can I execute a timer in the background without blocking the ui and video recording and also update the TextView?

Update:

As suggested, I have now implemented a Live data observer, but I still have the same problem, app crashes and there's nothing in logcat.

    fun startTimer(initial: String): MutableLiveData<String> {
        timer = Timer()
        timerCounterText.value = initial
        viewModelScope.launch(Dispatchers.IO) {
            timer?.scheduleAtFixedRate(timerTask {
                timerCounter += 1u
                timerCounterText.value = (timerCounter / 60u).toString().padStart(2, '0') + ":" +
                        (timerCounter % 60u).toString().padStart(2, '0')
            }, 1000, 1000)
        }
        return timerCounterText
    }

subscribing from activity:

cameraViewModel.startTimer().observe(this) { timeCount -> timerText.text = timeCount }

Solution

  • You are updating the textview on IO thread which only should be done Main thread, and hence the crash. You can read the exception reason in logcat.

    Secondly, you should never pass view instance to viewModel, rather use livedata or flow to listen data changes and act accordingly.

    This codelab example will help you

    https://developer.android.com/codelabs/basic-android-kotlin-training-livedata#0