일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 도약연계
- 조립 후 재부팅
- 플러터 #안드로이드 #플레이콘솔 #앱내리기
- 안드로이드 #코틀린 #코루틴 #콜백 #채널
- 도약전환
- Flutter #Stream
- Flutter #Stream #dart
- 희망적금전환
- 청년도약계좌환승
- flutter #dart #stream
- 도약계좌전환
- 희망적금연계
- Today
- Total
Flutter 개발 상자
[Android] Coroutine과 CallBack을 동시에 사용해보자 본문
(선행지식 : 코틀린 기본문법, 코루틴 기초, retrofit2 혹은 콜백에 대한 이해)
최근에 개발을 하면서 굉장히 골치아픈 일이 있었다.
코루틴을 이용해서 긴~작업이 걸리는 일들을
job1 -> job2 -> job3....
이런식으로 연속적으로 처리하고 있었는데
그 사이에 자체적으로 Executorservice - Callback 으로 비동기 처리를 한 라이브러리를 사용해서
job1 -> job2 -> Callback -> job3...
이런식으로 코루틴 블록안에서 콜백을 받아야 하는 일이 생겨버렸다.
Executorservice는 자체적으로 작업 쓰레드를 생성하기때문에 당연히 코루틴과는 별개로 돌아가서
어떻게해야할지 많은 고민이 되었는데
Channel을 이용해서 손쉽게 처리하는 방법이 있었다.
class MainActivity : AppCompatActivity() {
lateinit var mainJob: Job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainJob = CoroutineScope(Dispatchers.Default).launch {
launch {
delay(1000)
Log.d("@@@", "작업1 완료 !!!")
}.join()
launch {
delay(2000)
Log.d("@@@", "작업2 완료 !!!")
}.join()
// 이곳에서 retrofit 통신을 완료한 후에 작업을 해야함
launch {
delay(3000)
Log.d("@@@", "작업3 완료 !!!")
}.join()
Log.d("@@@", "모든 작업 완료 !!!")
}
}
}
우선 코루틴을 이용해서 시간이 오래 걸리는 작업을 순차적으로 처리하는 예제 코드를 작성하였다.
나의 목표는 코루틴과 관련없이 자체 쓰레드로 돌아가는 레트로핏을
작업2와 작업3 사이에 끼워넣고, 통신이 완료 된 후에 작업3을 진행하도록 하려고 한다.
레트로핏의 클라이언트 클래스나 인터페이스는 생략하겠다.
class MainActivity : AppCompatActivity() {
lateinit var mainJob: Job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainJob = CoroutineScope(Dispatchers.Default).launch {
launch {
delay(1000)
Log.d("@@@", "작업1 완료 !!!")
}.join()
launch {
delay(2000)
Log.d("@@@", "작업2 완료 !!!")
}.join()
// 이곳에서 retrofit 통신을 완료한 후에 작업을 해야함
downloadVideo("Big_Buck_Bunny_1080_10s_1MB.mp4")
launch {
Log.d("@@@", "작업3 완료 !!!")
}.join()
Log.d("@@@", "모든 작업 완료 !!!")
}
}
private fun downloadVideo(url: String) {
RetrofitService.apiInterface.fileDownload(url).enqueue(object: Callback<ResponseBody?> {
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
Log.d("@@@", "통신 실패")
}
override fun onResponse(call: Call<ResponseBody?>, response: Response<ResponseBody?>) {
Log.d("@@@", "다운로드 완료")
}
})
}
}
새롭게 짠 코드, 비교를 위해서 작업3의 딜레이코드를 삭제했다.
레트로핏은 GET 방식으로
test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4
해당 주소에서 동영상 파일을 Responsbody로 다운받을 예정이다.
이를 실행해보면
위와같이 다운로드가 끝나기 전에 작업3이 실행되어 버린다.
이번에는 채널을 추가해서 작업 순서를 제어해보자.
package com.example.coroutinecallback
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
lateinit var mainJob: Job
val downloadChannel = Channel<Int>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainJob = CoroutineScope(Dispatchers.Default).launch {
launch {
delay(1000)
Log.d("@@@", "작업1 완료 !!!")
}.join()
launch {
delay(2000)
Log.d("@@@", "작업2 완료 !!!")
}.join()
// 이곳에서 retrofit 통신을 완료한 후에 작업을 해야함
downloadVideo("Big_Buck_Bunny_1080_10s_1MB.mp4")
downloadChannel.receive()
launch {
Log.d("@@@", "작업3 완료 !!!")
}.join()
Log.d("@@@", "모든 작업 완료 !!!")
}
}
private fun downloadVideo(url: String) {
RetrofitService.apiInterface.fileDownload(url).enqueue(object: Callback<ResponseBody?> {
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
Log.d("@@@", "통신 실패")
mainJob.cancel()
}
override fun onResponse(call: Call<ResponseBody?>, response: Response<ResponseBody?>) {
Log.d("@@@", "다운로드 완료")
downloadChannel.offer(0)
}
})
}
}
통신이 실패했을때 콜백에서는 메인잡을 종료시키고
통신이 성공했을때 콜백에서는 채널에 0값을 주도록 하였다.
그리고 코루틴 내에서는 값이 들어오기 전까지 계속 대기상대를 유지하게되고
통신이 성공해서 값이 들어온 이후에 작업3을 실행하게 된다.
채널 하나 추가했을 뿐인데
콜백과 코루틴이 연결되었다. 와~이!
레트로핏을 예시로 들었지만 사실 레트로핏은 코루틴을 지원하기때문에
위와같이 쓸 필요는 없고
기타 라이브러리를 사용하는데 콜백을 사용하는 라이브러리라면
이런식으로 채널로 코루틴과 연결시켜주는걸 생각해볼 수 있겠다.