ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 코루틴 (Coroutine Builder) 코드
    안드로이드 학습/Android 기술면접 대비 2024. 11. 18. 13:16

    Coroutine Builder에는 주로 4가지가 있다. 

    1. launch 

    • 사용 목적: 결과를 반환하지 않고 코루틴을 실행.
    • 특징:
      • 반환값이 없는 Job 객체를 반환함.
      • 주로 fire-and-forget 작업(결과보다는 실행 자체가 중요한 작업)에 적합.
      • 예외가 발생해도 기본적으로 상위 코루틴에 전달됨.
    private fun coroutineLaunch() {
        val sb = StringBuilder()
        runBlocking {
            setStringWithStringBuilder(sb, "1. Thread Name : ${Thread.currentThread().name}", resultTextView)
            val result = launch {
                setStringWithStringBuilder(sb, "2. Thread Name : ${Thread.currentThread().name}", resultTextView)
                delay(1000L) // 지연 후 다시 이 코루틴을 재개
                setStringWithStringBuilder(sb, "3. Thread Name : ${Thread.currentThread().name}", resultTextView)
            }
            setStringWithStringBuilder(sb, "4. Thread Name : ${Thread.currentThread().name}", resultTextView)
            result.join()
            setStringWithStringBuilder(sb, "5. Thread Name : ${Thread.currentThread().name}", resultTextView)
        }
        setStringWithStringBuilder(sb, "6. Thread Name : ${Thread.currentThread().name}", resultTextView)
    }

     

    join()이나 run() 메소드를 이용해서 결과값을 먼저 나오게도 가능하다. 

     

    1 > 4 > 2 > 3 > 5 > 6 순서로 실행된다. 

    2. async

    • 사용 목적: 결과를 반환하는 코루틴을 실행.
    • 특징:
      • Deferred 객체를 반환하며, await()를 호출해 결과를 얻을 수 있음.
      • 주로 비동기적인 연산 작업에서 사용.
      • 결과를 기다리기 위해 명시적으로 await()를 호출해야 함.
    private fun coroutineAsync() {
        val myCharacter = CoroutineCharacter(null, null, null)
        val sb = StringBuilder()
        runBlocking {
            myCharacter.name = "John"
            setStringWithStringBuilder(sb, "1. myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineAsync", "1. $myCharacter")
    
            val result = async {
                delay(1000L)
                myCharacter.weapon = "sword"
                setStringWithStringBuilder(sb, "2. myCharacter : $myCharacter", resultTextView)
                Log.d("coroutineAsync", "2. $myCharacter")
    
            }
            myCharacter.age = 11
            setStringWithStringBuilder(sb, "3. myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineAsync", "3. $myCharacter")
    
            result.await()
            setStringWithStringBuilder(sb, "4. myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineAsync", "4. $myCharacter")
    
        }
    }

     

    결과 :

    1. CoroutineCharacter(name=John, age=null, weapon=null) 

    3. CoroutineCharacter(name=John, age=11, weapon=null)

    2. CoroutineCharacter(name=John, age=11, weapon=sword)
    4. CoroutineCharacter(name=John, age=11, weapon=sword)

     

    1,3번 먼저 실행한 후 중간에 await이 있기 때문에 async 내부 코드 실행 후 나머지 코드가 실행된다.

    3. runBlocking

    코루틴을 지원하지 않는 코드(예: 일반 함수)에서 코루틴 블록을 동기적으로 실행하기 위해 사용.

    • 새로운 코루틴을 시작하고, 그 코루틴이 완료될 때까지 현재 스레드를 블록(block) 함.
    • 주로 테스트나 진입점(main 함수)에서 사용.
    • 실행 중인 스레드를 잠시 멈추기 때문에 메인 스레드에서 과도하게 사용하면 성능 문제가 발생할 수 있음.

    5초이상 작업이 발생할 경우 시스템에 의해 ANR이 발생할 수 있다.

    private fun coroutineRunBlocking() {
        val myCharacter = CoroutineCharacter(null, null, null)
        val sb = StringBuilder()
        myCharacter.name = "John"
        setStringWithStringBuilder(sb, "1.myCharacter : $myCharacter", resultTextView)
        Log.d("coroutineRunBlocking", "1. $myCharacter")
    
        runBlocking {
            delay(1000L)
            myCharacter.weapon = "sword"
            setStringWithStringBuilder(sb, "2. myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineRunBlocking", "2. $myCharacter")
    
        }
        myCharacter.age = 11
        setStringWithStringBuilder(sb, "3. myCharacter : $myCharacter", resultTextView)
        Log.d("coroutineRunBlocking", "3. $myCharacter")
    
    }

     

    결과

    1. CoroutineCharacter(name=John, age=null, weapon=null)
    2. CoroutineCharacter(name=John, age=null, weapon=sword)
    3. CoroutineCharacter(name=John, age=11, weapon=sword)

     

    runBlocking 같은 경후 현재 Thread도 멈추고 실행 되기 때문데 1,2,3번의 순서대로 실행된다.

    4. withContext 

    • 사용 목적: 코루틴 내부에서 특정 디스패처(예: Dispatchers.IO, Dispatchers.Main)로 컨텍스트를 전환하기 위해 사용.
    • 특징:
      • 코루틴 내부에서만 사용 가능.
      • 호출되는 동안 비동기적으로 실행되며, 현재 코루틴의 진행을 일시 중단(suspend)함.
      • 컨텍스트를 전환하고 작업이 완료될 때까지 기다린 후 원래 컨텍스트로 돌아감.
      • async와 차이점은 async는 결과 값을 얻으로면 await()를 호출해야 하지만 withContext는 처음부터 결과 리턴까지 대기하는 형태
    private fun coroutineWithContext() {
        val myCharacter = CoroutineCharacter(null, null, null)
        val sb = StringBuilder()
        runBlocking {
            myCharacter.name = "John"
            setStringWithStringBuilder(sb, "myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineWithContext", "1. $myCharacter")
    
            withContext(Dispatchers.IO) {
                delay(1000L)
                myCharacter.weapon = "sword"
                setStringWithStringBuilder(sb, "myCharacter : $myCharacter", resultTextView)
                Log.d("coroutineWithContext", "2. $myCharacter")
    
            }
            myCharacter.age = 11
            setStringWithStringBuilder(sb, "myCharacter : $myCharacter", resultTextView)
            Log.d("coroutineWithContext","3. $myCharacter")
    
        }
    }
    

     

    결과 : 

    1. CoroutineCharacter(name=John, age=null, weapon=null)
    2. CoroutineCharacter(name=John, age=null, weapon=sword)
    3. CoroutineCharacter(name=John, age=11, weapon=sword)

Designed by Tistory.