Giter VIP home page Giter VIP logo

til's Introduction

TIL

This is for recording 'Today-I-Learned'
Postings are managed on 'Issues' catergory

til's People

Contributors

dlqkfzlr avatar

Watchers

 avatar

til's Issues

ViewModel에서 Retrofit2 & coroutine 사용시 알아둬야할 포인트

ViewModel에서 Retrofit2 & Coroutine 사용시 알아둬야할 포인트

from 태환님 블로그

class SearchViewModel @ViewModelInject constructor(
    private val repository: GiphyRepository
) : ViewModel() {
    fun searchGiphy(query: String) {
        viewModelScope.launch {
            withContext(Dispatchers.IO){
                val response = repository.requestToSearchGiphy(query, 10, 0)
            }
        }
    }
}

ViewModel에서 suspend메서드를 호출할때

viewModelScope.lauch{ } 를 통해 블럭 내에서 suspend메서드를 호출함.

하지만 이때 viewModelScope.lauch내에서 굳이 Dispatchers.IO로 설정할 필요가 없음!

viewModelScope는 내부적으로 Main Scheduler를 사용하기 때문에,

당연하게도 withContext(Dispatchers.IO)를 적용해줘야되지 않을까라고 생각할 수 있지만

이는 잘못된 생각이다.

// retrofit2의 KotlinExtensions.kt 내부
suspend fun <T : Any> Call<T>.await(): T {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        if (response.isSuccessful) {
          val body = response.body()
          if (body == null) {
            val invocation = call.request().tag(Invocation::class.java)!!
            val method = invocation.method()
            val e = KotlinNullPointerException("Response from " +
                method.declaringClass.name +
                '.' +
                method.name +
                " was null but response body type was declared as non-null")
            continuation.resumeWithException(e)
          } else {
            continuation.resume(body)
          }
        } else {
          continuation.resumeWithException(HttpException(response))
        }
      }
      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

retrofit2의 KotlinExtensions.kt파일을 살펴보면 Coroutine사용시 Callback을 처리하는 방법이 기술되어 있다.

enqueue를 사용해서 onResponse를 받아오게 되는데, 이때 onResponse는 자동으로 Main스케줄러로 동작을 한다.

따라서 위처럼 IO스케줄러를 사용하려 해도 어짜피 Main스케줄러를 사용하게 된다.

요약하자면 백그라운드 스레드에서 네트워크 통신을 하고

그걸 onResponse로 받을때는 메인 스레드에서 작업을 하고

호출한 Coroutine쪽으로 결과값을 return 해주는 프로세스를 거친다.

그래서 Room을 사용하여 캐싱이 필요한 경우가 아니라면 굳이 IO스케줄러를 사용할 필요가 없다.

Coroutine 개념

1. 개념

(1) Coroutine이란 무엇인가?

By Wiki →

코루틴은 (컴퓨터 프로그램 구성 요소 중 하나로 )

비선점형(non-preemptive) 멀티태스킹을 수행하는

일반화한 서브루틴(Subroutine)이다.

  • 비선점형 멀티태스킹

⇒ 일단, 멀티태스킹은 여러 작업을 동시에 수행하는 것처럼 보이거나 실제로 동시에 수행하는 것.

그럼 비선점형이란?

'멀티태스킹의 각 작업을 수행하는 참여자들의 실행을

운영체제(OS)가 강제로 일시 중단시키고 다른 참여자를 실행하게 만들 수 없다'는 뜻이다.

즉, 각 참여자들이 서로 자발적으로 협력해야만 비선점형 멀티태스킹이 제대로 작동할 수 있다.

  • 서브루틴 (**"함수"**와 동일한 의미)

⇒ 여러 명령어를 모아 이름을 부여해서 반복 호출할 수 있게 정의한 프로그램 구성 요소

[결론]

Co + (sub)routine ; 쉽게 말해 협동 루틴으로

서로 협력해서 실행을 주고받으면서 작동하는 여러 Subroutine을 말한다.

subroutine


(2) Android에서 Coroutine이 중요하고 쓰는 이유는?

비동기 작업을 Sequential하게 쓸 수 있다.

Google I/O 19'에 나온 좋은 예시로 설명

1번째 방법) 이렇게 Coroutine없이 (=suspend함수없이) sequential하게 서버 통신을 하게 된다면,

UIthread에서 fetchUser가 진행되기 때문에 응답을 받을 때까지 blocking이 일어나게 되어서

ANR이 일어나게 됨.

blocking

2번째 방법) 비동기로 Callback을 사용하여 다른 Thread로 서버 응답을 받음.

이렇게 하면 동작은 하지만 코드가 간결하지 않음

async

3번째 방법) suspend함수로 Coroutine을 사용해서 서버 응답을 받음.

coroutine

결과적으로 비동기 작업을 Sequential하게 코드로 작성이 가능해서 가독성이 매우 좋다.

suspend resume

즉, suspend시에 pause상태로 바뀌고 완료되면 중단됐던 시점부터 resume한다.

suspend의 기능을 콜백을 가지는 것으로 이해해도 좋다.

그리고 resume은 callback이 작동할때와 동일함.

(3) 어떻게 이렇게 코드가 구현이 가능할까?

바로 suspend함수 내부에는 Continuation이라는 객체가 존재하기 때문이다.

참고) https://tv.naver.com/v/15354002/list/629240

2. Dispatchers

(1) 개념

Dispatchers에 대해 알기 전에 CoroutineContext에 대한 이해가 우선이다.

CoroutineContext란 Coroutine을 어떻게 처리할 것인지에 대한 여러가지 정보의 집합니다. CoroutineContext의 주요 요소로는 Job과 Dispatcher가 있다.

이 중 Dispatcher는 '어떤 Thread에서 해당 coroutine을 실행할지'에 대한 정보를 담고 있다.

(2) 종류

  • Default: CPU

CPU-intensive한 작업을 할 때 사용!

ex) 몇백개의 element를 변환하는 작업, DiffUtil사용시 등등

  • IO: Network & Disk

Network & Disk와 관련된 Blocking 작업을 할 때 사용!

ex) File을 write하는 작업, Socket을 read하는 작업

  • Main: 안드로이드의 경우 UI thread

UI이벤트에 대한 response를 실행하야 하는 작업에 사용!

Google은 suspend의 함수의 시작점에서 사용하는걸 추천.

그러면 간단한 작업시 UI thread에서 모든걸 끝낼 수 있기 때문.

I/O작업이 필요하다면 그때 withContext를 사용해서 Dispatchers를 변경하면 됨

runBlocking과 coroutineScope의 차이

Issue

runBlocking과 coroutineScope내의 launch는 모두 블록내에서 CoroutineScope를 scope로 사용한다.
또한 블록내의 body와 children의 작업이 모두 끝날때까지 기다린다는 공통점을 가지고 있다.
하지만 이 둘은 엄연히 다른 함수이다.
runBlocking은 regular function
coroutineScope는 suspend function

따라서, runBlocking은 내부작업의 waiting을 위해 현재 스레드를 실제로 block하지만,
coroutineScope는 block하는 것이 아니라 suspend하기 때문에 작업이 안끝나도 기반 스레드를 다른 용도를 위해 release한다.

예시코드

fun main() = runBlocking { // this: CoroutineScope
    launch {
        delay(2000L)
        println("Task from runBlocking")
    }
    coroutineScope { // Creates a coroutine scope
        launch {
            delay(5000L)
            println("Task from nested launch")
        }
        delay(1000L)
        println("Task from coroutine scope") 
    }
    println("Coroutine scope is over") 
}

출력결과

Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over

설명

위의 코드를 보면 coroutineScope는 suspend 함수이기 때문에
내부 launch의 코드 println("Task from nested launch") 가 아직 끝나지 않았음에도
coroutineScope 외부의 println("Task from runBlocking") 를 실행한다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.