본문 바로가기
개발

[코틀린] coroutine async await 사용

by kks950115 2024. 4. 8.
728x90

맵을 구현하면서 렉을 줄이기 위해 화면 안에 마커만 표시하기로 했다.

마커는 그냥 보여줬다 안보여줬다만 하면 되는데 문제는 클러스터러였다.

이걸 만들 당시에는 네이버맵에서 클러스터링을 지원하지 않았어서 tednavercluster라는 라이브러리를 썼었다.

지금은 클러스터링을 지원한다. 프로젝트 진행중에 생겨서 너무 빡쳤었다. 좀만 일찍 냈으면 라이브러리를 안써도 됐잖아 ㅠㅜ

아무튼 라이브러리에 데이터를 넣으면 표시해주는데 객체가 들어있는 배열형태로 넣어주다보니 처리하는데 시간이 꽤나 오래 걸렸다.

 

그래서 메인 스레드에서만 돌리기에는 작업량이 많아서 속도가 너무 느린 거 같아 코루틴을 활용하여 처리하기로 했다.

 

아래 코드가 코루틴을 사용한 부분이다.

 

 private fun updateCluster(
        naverMap: NaverMap?,
        campData: MutableList<LocationBasedListItem>,
        mMarkers: MutableList<Marker>
    ) {
	// 지도 상에 마커 전부 삭제
        mMarkers.forEach {
            hideMarker(it)
        }

        CoroutineScope(Dispatchers.Default).launch {
		//클러스터러에 있는 아이템 전부 삭제
            tedNaverClustering?.clearItems()
            //for문을 나눠서 돌리기 위해 인덱스를 4로 나누었다
            val middleIdx = campData.size / 4
			//job 실행
            val job1 = async {
                addCampData(campData, naverMap, 0, middleIdx)
            }
            val job2 = async {
                addCampData(campData, naverMap, middleIdx, middleIdx * 2)
            }
            val job3 = async {
                addCampData(campData, naverMap, middleIdx * 2, middleIdx * 3)
            }
            val job4 = async {
                addCampData(campData, naverMap, middleIdx * 3, campData.size)
            }
           	// 한번에 처리하기 위해 list에 담음
            val list = listOf(job1, job2, job3, job4)
            list.awaitAll()
        }
    }

    private fun addCampData(
        campData: MutableList<LocationBasedListItem>,
        naverMap: NaverMap?,
        startIdx: Int,
        endIdx: Int
    ) {
        val mapBounds = naverMap?.contentBounds
        val clustering = mutableListOf<LocationBasedListItem>()
        for (i in startIdx until endIdx) {
            val lat = campData[i].mapY
            val lon = campData[i].mapX
            val position = LatLng(lat!!.toDouble(), lon!!.toDouble())
            //Log.d("test","포지션= ${position}")
            if (mapBounds?.contains(position) == true) {
                clustering.add(campData[i])
            }
        }
        tedNaverClustering?.addItems(clustering)
    }

 

async는 비동기 처리를 위한 함수이므로 코루틴 영역에서만 실행이 가능하며, 작업이 완료될 시 값을  Deffered 인스턴스를 반환한다. Deffered는 async로 받아온 결과값을 처리할 수 있게 해주는 인터페이스다.

 

비동기 작업이라면 실행순서를 조절해야하는 순간이 있다. 예를 들자면 a,b,c 작업이 있다면 a,b가 완료 된 다음에 c를 완료해야하는데  c가 실행되려면 a,b의 결과가 필요할 때 말이다. 

이런 경우에 await()을 사용하면 된다. await()은 비동기작업이 실행될 때까지 기다리게 만든다. 

 

내 경우는 for문이 너무 오래 걸리는 것 같아서 4개로 나눠서 돌렸다. 나눠서 돌려도 결과는 하나로 받아야했기 때문에 await을 써야했다.

위에 코드를 예로 들자면

job1, job2, job3, job4의 결과를 동시에 받기 위해 리스트에 job을 넣었다.

그리고 job들이 모두 실행되기 전까지 기다리도록 awaitAll() 을 사용했다. 

 

그럼 코루틴이 끝나면 비동기로 for문이 모두 실행된 것을 확인할 수 있다.

728x90
반응형

댓글