안드로이드에서 Kotlin coroutine (Async, Await)을 사용하여 Sakut과 HTTP 통신 (비동기 처리)

소개



Kotlin을 사용하여 Android 앱을 개발하고 있습니다.
REST API를 두드려 얻은 결과를 바탕으로 UI를 업데이트 할 때
  • HTTP 통신은 메인 스레드 외부에서 수행되어야합니다 (비동기 처리 필요)
  • 취득한 json 데이터의 퍼스가 번거로움( Gson , 만약 등 여러가지 라이브러리는 있지만, json의 데이터 스킴을 정의하는 것이 귀찮다.)
  • UI 업데이트는 메인 스레드에서 수행되어야합니다 (AsyncTask 등에서 비동기 처리를 수행하면 처리가 약간 길어집니다).

    등의 제약이 있기 때문에, 개인적으로 상기를 편하게 실시할 수 있는 범용 스니펫을 작성했습니다.

    이번에 작성한 스니펫의 포인트는
  • HTTP 통신에는 OKHttp3 을 사용
  • json의 퍼스에, 데이터 모델의 정의 불필요한 minimal-json를 사용
  • 비동기 처리에 Async, Await ( kotlin.coroutines ) 사용

  • 2018/12/2 업데이트



    Kotlin1.3이 출시되었고 coroutines가 정식 버전이되었습니다.
    Kotlin1.3으로 버전을 올리면 약간의 코드 수정이 필요합니다.

    Kotlin1.3에 대응한 수정판은 엉망이므로 별도 페이지에 정리했습니다.
    Android + Kotlin1.3 coroutines에서 비동기 HTTP 통신

    Kotlin 1.2 계를 일부러 사용하는 이유가없는 분은 위를 참조하는 것이 좋을까 생각합니다!

    사전 준비



    Gradle 설정



    사용할 라이브러리 종속성 해결을 위해 다음 설명을 app의 build.gradle에 추가합니다.
    Kotlin coroutine용 라이브러리는 2018년 9월 21일 현재 최신 0.26.1을 사용합니다.

    kotlin-coroutines 0.26.1에서는 파괴적인 갱신이 여러가지 행해지고 있는 것 같습니다.

    참고
    kotlin-coroutines 0.26.1에서 파괴적인 업데이트

    app/build.gradle
    dependencies {
        implementation 'com.squareup.okhttp3:okhttp:3.11.0'  //http通信ライブラリ
        implementation 'com.eclipsesource.minimal-json:minimal-json:0.9.5' //jsonパースライブラリ
        def coroutines_version = '0.26.1' //kotlinコルーチン用ライブラリ(async, await)のバージョン
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" //kotlinコルーチン用ライブラリ(async, await)
        implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" //kotlinコルーチン用ライブラリ(async, await)
    }
    

    사용할 Kotlin의 버전 변경



    프로젝트의 build.gradle에서 Kotlin coroutine을 사용하기 위해 Kotlin 버전을 변경합니다.

    build.gradle
    ext.kotlin_version = '1.2.61' //Kotlin coroutineを使う際にバージョンを変更する必要あり
    

    Kotlin coroutine의 사용을 gradle.properties에 설명합니다.

    gradle.properties
    //Kotlin coroutineを使うのに必要
    kotlin.coroutines=enable
    

    비동기 처리에 대응하는 HTTP 통신 처리 작성



    이번에는 HTTP GET을 수행하는 메소드를 정의했습니다.

    HttpUtil.kt
    class HttpUtil {
        //叩きたいREST APIのURLを引数とします
        fun httpGET(url : String): Deferred<String?> = GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT, null, {
            val client = OkHttpClient()
            val request = Request.Builder() 
                    .url(url)
                    .build()
    
            val response = client.newCall(request).execute()
            return@async response.body()?.string() //asyncを使って非同期処理にします
        })
    }
    

    HTTP GET 결과를 사용하여 UI 업데이트



    이번에는 버튼을 클릭하면 HTTP GET 처리가 실행되고 결과를 TextView에 반영하는 처리를 썼습니다.

    MainActivity.kt
    class MainActivity : AppCompatActivity() {
        val URL = "http://weather.livedoor.com/forecast/webservice/json/v1?city=400040" //サンプルとしてライブドアのお天気Webサービスを利用します
        var result = ""
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val getButton = findViewById(R.id.button) as Button
            getButton.setOnClickListener(object : View.OnClickListener {
                override
                fun onClick(view: View) {
                    onParallelGetButtonClick()
                }
            })
        }
    
        //非同期処理でHTTP GETを実行します。
        fun onParallelGetButtonClick() = GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT, null, {
            val http = HttpUtil()
            val res = http.httpGET(URL).await()
            val result = Json.parse(res).asObject()
    
            val textView = findViewById(R.id.text) as TextView
            textView.setText(result.get("description").asObject().get("text").asString())
        })
    }
    

    결과



    HTTP GET을 비동기 처리로 실행하고 얻은 json을 TextView에 반영 할 수있었습니다.


    소감



    매우 간단하게 비동기 처리로 HTTP 통신을 실현할 수 있었습니다.
    minimal-json은 has계의 메소드가 없거나와 멋지지 않은 부분도 있습니다만 바삭하게 움직이고 싶을 때에는 이번 라이브러리군의 조합은 좋은 느낌일까라고 생각합니다.

    좋은 웹페이지 즐겨찾기