Kotlin Coroutines 안드로이드 OnClick에 활용하기



개인 광고 영역

이전 글에서 Coroutines과 안드로이드에 적용하기 위한 플러그인 적용 방법을 알아보았다.

이번 글에서는 적용한 코드를 좀 더 자세하게 알아보고, Android에서 onClick과 함께 사용할 경우 유용한 Coroutine 사용 방법을 알아본다.

Countdown 코드 살펴보기

이전 글에 사용한 샘플 코드를 그대로 가져와보았다.

fun setup() {
    val job = GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread
        for (i in 10 downTo 1) { // countdown from 10 to 1
            tv_message.text = "Countdown $i ..." // update text
            delay(500) // wait half a second
        }
        tv_message.text = "Done!"
    }
    fab.setOnClickListener {
        job.cancel() // cancel coroutine on click
    }
}

위 코드를 통해 이번 글에서 알아볼 부분을 분리해보았다.

  • 코루틴의 스레드 형태를 어떻게 가져갈지 정의(Dispatchers.Main, Dispatchers.Default)

위와 같은 코드를 확인할 수 있다. 각각을 구분하여 글을 정리하고, onClick에서 사용할 부분을 좀 더 정리해본다.


Android OnClick에 따른 적절한 coroutine 처리 - 일단 알아보자

onClick을 아래와 같이 생성해보았다. 아래 코드로는 무슨 일이 사실 일어나는지 알 수 없다.

private var count = 0
btn_start.setOnClickListener {
    count++
    CoroutineScope(Dispatchers.Main).launch {
        for (i in 10 downTo 1) { // countdown from 10 to 1
            tv_message.text = "Now Click $count Countdown $i ..." // update text
            delay(500) // wait half a second
        }
        tv_message.text = "Done!"
    }
}

이제 앱을 실행하고, start 버튼을 N 번 눌러본다. 아래 그림처럼 계속적인 버튼을 눌렀다면 무슨 일이 일어날까?

click

결과는 아래와 같다. 결과의 이해를 돕기 위해 그림과 텍스트를 추가해보았다. 결과는 병렬로 계속 움직인다.

Now Click 1 Countdown 5 ...
Now Click 2 Countdown 5 ...
Now Click 1 Countdown 4 ...
Now Click 3 Countdown 5 ...
...
Now Click 1 Countdown 1 ...
Done!
Now Click 5 Countdown 5 ...
Now Click 4 Countdown 4 ...
Now Click 3 Countdown 1 ...
Done!

첫 번째 클릭의 결과로 Now Click 1 Countdown 5 … 이 먼저 보이고, 이어서 버튼을 누르면 Now Click 2 Countdown 5 …이 잠깐 보였다가 다시 1번이 노출된다. 이런식으로 반복적으로 클릭을 발생하면 버튼 누른 만큼 N 번의 결과물이 노출되는걸 확인할 수 있다. 좀 더 자세하게 그림을 참고하길 바란다.

coroutines-example-01

사용자 액션에 따라 무작위로 동작해야 하는 경우도 있지만, 보통 그렇지 않다. 이전 동작이 모두 끝나고 나면 다음 동작을 해야 하는 경우도 있고, 중간중간 사용자의 액션을 처리해야 하는 경우도 있다.


actor을 이용해보자

먼저 예를 들어보자.

네트워크를 통해 데이터를 받아오고, 이를 노출한다.

이때 위와 같이 N 번 클릭을 무작위로 받는 코드를 작성한다면? 결과는 당연히 네트워크도 N 번 동작하게 된다. 기존 이벤트를 취소하는 것도 적절한 방법은 아니다.

그래서 actor을 이용할 수 있는데, 아래와 같이 코드를 수정해보았다.

private var count = 0
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)

  btn_start.onClick {
    count++
    for (i in 10 downTo 1) { // countdown from 10 to 1
        tv_message.text = "Now Click $count Countdown $i ..." // update text
        delay(500) // wait half a second
    }
    tv_message.text = "Done!"
  }
}

private fun View.onClick(action: suspend (View) -> Unit) {
  // launch one actor
  val event = GlobalScope.actor<View>(Dispatchers.Main) {
    for (event in channel) action(event)
  }

  setOnClickListener {
    event.offer(it)
  }
}

위 코드는 여러 번 누르더라도 기존 action을 모두 처리하기 전에는 다음으로 넘어가지 않는다.

coroutines-example-02


마무리

간단하게 Android에서 Coroutine을 어떤 식으로 활용할 수 있을지 살펴보았다. RxJava를 활용한다면 throttleFirst의 형태를 만들어야 하겠지만 kotlin coroutine에서는 간단하게 Actor을 활용할 수 있다. 다만 GlobalScope가 아닌 매번 생성하는 CoroutineScope을 활용한다면 또 다른 이야기이긴 하다.



About Taehwan

My name is Taehwan Kwon. I have developed Android for 6 years and blog has been active for eight years.

Comments