Kotlin 앱 네트워크 요청 및 응답 기능 추가 - 간단한 Kotlin 앱 개발




안드로이드 자바 버전으로 만들었던 단축URL 앱을 Kotlin 버전으로 개발해 보겠습니다.
단축URL 자바 버전 설명은 아래 링크에 있습니다.


이번에 개발할 앱은 단축URL을 생성하는 앱입니다.
네이버 API를 사용해서 Kotlin과 retroift을 사용해서 단축URL을 생성하고 공유하는 앱을 개발할 것입니다.

단축URL API는 네이버 API를 사용합니다.
네이버 API를 설정하는 방법은 자바버전 단축URL 앱 만들기 1 에서 소개 했습니다.



단축URL 생성 앱
단축URL 생성 앱


Kotlin 설정

build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

build.gradle 의 plugin으로 kotlin-android 와 kotlin-android-extensions 를 추가합니다.
Kotlin 안드로이드 익스텐션은 코틀린을 사용할 때 유용한 도구를 지원합니다.

//기존 자바
TextView versionTextView = findViewById(R.id.version_text);
versionTextView.setText("ver" + BuildConfig.VERSION_NAME);

//Kotlin 안드로이드 익스텐션
version_text.text = "ver " + BuildConfig.VERSION_NAME

위 코드처럼 findViewById()로 뷰를 사용하고 있었지만, 익스텐션에서는 리소스의 id로 직접 접근해서 사용할 수 있기때문에 좀 더 편하게 개발할 수 있습니다.

Kotlin DTO, VO?

네이버 단축URL API를 응답받을 데이터 객체를 생성하겠습니다.
API 응답 객체로 abstract classdata class를 사용해서 구현할 수 있습니다.

Kotlin abstract class

응답 데이터 code, message 는 공통으로 사용할 수 있도록 abstract class를 이용해보겠습니다.
Kotlin은 class를 선언하면 디폴트로 final class입니다.
상속을 하려면 abstract class 또는 open class로 선언해야 됩니다.

abstract class ResponseData {
    val message: String ?= null
    val code: String ?= null
}

Kotlin data class

네이버 API 응답 데이터 hash, url, orgUrl data 객체로 생성합니다.
data 클래스는 DTO나 VO처럼 setter(), getter()를 자동으로 생성됩니다.
그리고 equals(), hashcode(), toString() 메서드를 자동으로 생성합니다.

data class ShortUrlData (
    val hash: String,
    val url: String ,
    val orgUrl: String
)

Kotlin 상속

data class: ResponseData() 하여 상속할 수 있습니다.
Kotlin으로 DTO나 VO를 만들때 data classabsract class를 사용하여 간단하게 선언할 수 있습니다.
자바라면 setter()getter(), equals()hashcode()toString() 를 개발자가 직접 작성하던 것을 data class 로 쉽게 선언할 수 있습니다.

data class ShortUrlResult(val result:ShortUrlData) : ResponseData()

Kotlin Retrofit Service?

Retrofit에서는 Service 라는 interface를 생성해야합니다.
Kotlin 함수는 "fun 함수명(...) : 리턴객체" 형태로 선언할 수 있습니다.
parameter는 "변수: 타입객체" 형태로 선언할 수 있습니다.
리턴타입이 변수 뒤에 있는것만 다르고 자바와 비슷합니다.

interface NaverService {
    @Headers(
        "X-Naver-Client-Id: ${NaverConsts.CLIENT_ID}",
        "X-Naver-Client-Secret: ${NaverConsts.CLIENT_SECRET}")
    @GET("/v1/util/shorturl")
    fun getShortUrl(@Query("url") url: String): Call<ShortUrlResult>
}

Retrofit 사용

Kotlin에서는 멤버변수를 선언할때 초기화가 필요합니다.
?= null 로 초기화를 하면 null으로 초기화 됩니다.
Kotilin은 null을 허용하지 않기때문에 ?를 사용해서 null로 초기화할 수 있습니다.

var는 읽기와 쓰기가 가능 변수입니다.
val은 읽기만 가능한 변수입니다.
아래 코드를 보면 읽기전용인 val client는 초기화 되지 않았어도 컴파일됩니다.
init {..} 으로 초기화되기 때문입니다.
init 블럭 안에서 초기화 코드를 넣을 수 있습니다.

class DataManager() {
    private var naverService : NaverService ?= null
    private val client: OkHttpClient

    init {
        client = OkHttpClient.Builder()
                    .addInterceptor(interceptor)
                    .build()

        createNaverApi()
    }

    private fun createNaverApi() {
        naverService = Retrofit.Builder()
                .baseUrl(NaverService.ENDPOINT)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(NaverService::class.java) //자바코드의 class 함수 사용 방법
    }
}

Kotlin에서 리스너(Listener) 사용하기

네이버 단축URL API를 요청해보겠습니다.
loadShorturl()은 url을 받아 call.enqueue()하고 응답을 받으면 람다표현식을 사용해서 success()error()를 콜백(callback)하도록 구현했습니다.

기존 자바에서는 리스너를 만들어서 콜백 받았지만, Kotlin에서는 람다표현식을 이용해서 손쉽게 만들 수 있습니다.
success: (ShortUrlData) -> Unit에서 리턴타입 Unit은 값을 반환하지 않는 것을 뜻합니다.
자바에서는 void success(ShorturlData data)와 같습니다.
retrofit에서 사용된 Callback을 받기위해 success()error()를 만들었습니다.

fun loadShorturl(url: String,
            success: (ShortUrlData) -> Unit,
            error: (Call<ShortUrlResult>, Throwable) -> Unit) {

    val call = naverService!!.getShortUrl(url)

    call.enqueue( object :Callback<ShortUrlResult> {

        override fun onResponse(call :Call<ShortUrlResult>?,
                                        response: Response<ShortUrlResult>?) {

                val data = response?.body()?.result             
                data?.let { success(data) }
        }
         
        override fun onFailure(call: Call<ShortUrlResult>?, t: Throwable?) {

                call?.let {
                    if (t != null) {
                        error(it, t)
                    }
                }
        }
    })
}

자바 Callback Listener -> object 키워드를 사용

retrofit의 Callback.java를 Kotlin에서 사용하려면 object 키워드로 위 코드처럼 사용합니다.
Kotlin에서는 함수를 오버라이드할 때는 overridefun 앞에 붙여야합니다.
자바에서는 null 일수 있기때문에 파라메터 call, response에 ? 를 붙여 null 유무를 표시해줍니다.

let 함수와 ?로 편하게 null 체크

변수에 ?를 붙이면 null 체크가 됩니다
response?.body() 에서 response가 null이 아니면 body()가 호출되고 null인경우 data에 null이 할당됩니다.

let함수와 ?를 이용해서 손쉽게 null처리가 가능합니다.
let 함수는 블럭 안으로 인자를 넘겨주는데 ?하고 같이 사용한다면, null이 아닌경우에만 블록안으로 넘겨서 사용할 수 있기때문에 null 체크에 유용합니다.
data?.let{...} 에서 data가 널인경우 let은 호출되지 않습니다.
let{...} 블럭 안으로 넘어오는 변수는 하나이기때문에 it 키워드로 받아 올 수도 있습니다.

val data = response?.body()?.result //?으로 null 체크
data?.let { success(data) } //null 이 아닌경우 블럭 실행
call?.let { error(it, t) } //it 사용

다음장에서는...

이번장에서는 Kotlin으로 retrofit을 사용하는 방법을 알아보았습니다.
다음장에서는 네이버 API를 호출해서 생성한 단축URL을 클립보드로 복사하거나 다른 앱으로 공유하는 Kotlin를 학습해 보겠습니다.

셈플앱은 아래 구글플레이에서 설치해 볼 수 있습니다.
다음장에서 Kotlin 전체 소스를 공유하겠습니다.

Get it on Google Play

이글은 제가 직접 공부하면서 정리한 자료입니다.
틀린 부분이 있거나 수정해야 될 부분이 있을경우 알려주시면 감사하겠습니다.^^



댓글

이 블로그의 인기 게시물

코틀린 (Kotlin) filter, map, all, any, count, find, groupBy, flatMap 함수 정리

코틀린 (Kotlin) 인터페이스 정리

RecyclerView 에서 notifyItemChanged()의 payload 이해하기