안드로이드 스튜디오 코루틴사용해 보기

개린이의 개발 노트·2023년 8월 2일
1

안드로이드 스튜디오에서 캘린더뷰 구현을 하던 중에 이상한 점을 발견했었다.

원래 내가 구현하고 싶은 로직은

  1. 서버로 부터 특정 날짜 정보를 가져온다.
  2. 가져온 정보를 변수에 저장
  3. 해당 변수를 이용해서 날짜 밑에 점을 찍는 클래스 추가 / 캘린더 날짜 밑에 점 찍기

그래서 이런 식으로 구현을 했다.

val year = today.year.toString()
val month = if(today.month + 1 < 10) "0" + (today.month + 1).toString() else (today.month + 1).toString()
val callDate = year + "-" + month
promiseDates = UpdatePlanDates(callDate)
eventDecorator = planDotDecorator(requireContext(), R.color.mainsub1, promiseDates) // 일정 있으면 날짜 밑에 점 찍기
binding.viewCanlendar.addDecorator(eventDecorator)

fun UpdatePlanDates(callDate : String) : ArrayList<Int>{
        
            Log.d("callDate","${callDate}")
            val responseDate = getRetrofit().create(RetrofitInterface::class.java) // 이걸 따로 빼내는 방법....
            val refreshToken = getRefreshToken(requireContext())
            responseDate.homepromiseshow(
                "Bearer $refreshToken",
                callDate
            ).enqueue(object :
                retrofit2.Callback<HomePlanShow> { // 서버와 비동기적으로 데이터 주고받을 수 있는 방법 enqueue사용
                override fun onResponse( // 통신에 성공했을 경우
                    call: Call<HomePlanShow>,
                    response: Response<HomePlanShow>
                ) {
                    if (response.isSuccessful) {
                        val resp = response.body()// 성공했을 경우 response body불러오기
                        Log.d("SIGNUP/SUCCESS", resp.toString())
                        Log.d("성공!","success")
                        promiseDates = resp!!.result.dates
                        return promiseDates
                    }
                    else{
                       return promiseDates
                    }
                }

                override fun onFailure(call: Call<HomePlanShow>, t: Throwable) { // 통신에 실패했을 경우
                    Log.d("SIGNUP/FAILURE", t.message.toString()) // 실패한 이유 메세지 출력
                    return promiseDates
                }

            })
        }

    

그런데 이렇게 구현을 해보니 서버에서 정보를 제대로 가져와도 달력 날짜 밑에 점이 찍히지 않는 이상한 현상이 발생했다.

그래서 로그를 찍어보니

분명히 코드상에는 서버로부터 정보를 가져온 뒤에 점을 찍는 메소드를 진행하도록 설계되었는데 로그상에는 점을 찍는 메소드가 먼저 끝나고 나서야 서버로 부터 정보를 가져오는 것도 끝나는 이상한 현상이 진행되었다.

그래서 어떻게 하면 순서를 제대로 제어할 수 있지 하다가 코루틴이라는 개념을 알게 되었고,
이 블로그에서 유용한 정보를 얻을 수 있었다.

https://wooooooak.github.io/kotlin/2019/08/25/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B0%9C%EB%85%90-%EC%9D%B5%ED%9E%88%EA%B8%B0/

그래서 다음과 같이 코드를 수정하였다.

 CoroutineScope(Dispatchers.Main).launch {
            val year = today.year.toString()
            val month = if(today.month + 1 < 10) "0" + (today.month + 1).toString() else (today.month + 1).toString()
            val callDate = year + "-" + month
            promiseDates = UpdatePlanDates(callDate)
            eventDecorator = planDotDecorator(requireContext(), R.color.mainsub1, promiseDates) // 일정 있으면 날짜 밑에 점 찍기
            binding.viewCanlendar.addDecorator(eventDecorator)
        }

suspend fun UpdatePlanDates(callDate : String) : ArrayList<Int>{
        return suspendCoroutine { continuation->
            Log.d("callDate","${callDate}")
            val responseDate = getRetrofit().create(RetrofitInterface::class.java) // 이걸 따로 빼내는 방법....
            val refreshToken = getRefreshToken(requireContext())
            responseDate.homepromiseshow(
                "Bearer $refreshToken",
                callDate
            ).enqueue(object :
                retrofit2.Callback<HomePlanShow> { // 서버와 비동기적으로 데이터 주고받을 수 있는 방법 enqueue사용
                override fun onResponse( // 통신에 성공했을 경우
                    call: Call<HomePlanShow>,
                    response: Response<HomePlanShow>
                ) {
                    if (response.isSuccessful) {
                        val resp = response.body()// 성공했을 경우 response body불러오기
                        Log.d("SIGNUP/SUCCESS", resp.toString())
                        Log.d("성공!","success")
                        promiseDates = resp!!.result.dates
                        continuation.resume(promiseDates)
                    }
                    else{
                        continuation.resumeWithException(Exception("Response not successful"))
                    }
                }

                override fun onFailure(call: Call<HomePlanShow>, t: Throwable) { // 통신에 실패했을 경우
                    Log.d("SIGNUP/FAILURE", t.message.toString()) // 실패한 이유 메세지 출력
                    continuation.resumeWithException(t)
                }

            })
        }

    }

우선 CoroutineScope 안에서 코드들이 정상적으로 진행되다가 suspend함수를 만나면 그 밑에 로직은 진행이 안되게 되고 CoroutineScope밖에서 다른 코드들이 진행이 된다. 그런 다음 suspend함수가 진행이 끝나게 되면 CoroutineScope안 코드들이 진행이 되는 것이다.

아직 코루틴을 쓰는 것이 익숙하지 않지만 많이 쓰다보면 분명히 코틀린 코드들을 내 입맛대로 제어하는게 가능해질 것 같다....(May be?)

profile
개발 처음 시작함..... 그러니 잘못되거나 다소 이해안가는 코드들도 있을 수 있습니다 이점 양해 부탁드려요

2개의 댓글

comment-user-thumbnail
2023년 8월 2일

유익한 글이었습니다.

1개의 답글