Code

정식 언어로 채택된 Kotlin, Android에 미친 영향은?

July 14, 2019

정식 언어로 채택된 Kotlin, Android에 미친 영향은?

구글 안드로이드 개발에서 Kotlin을 지원한지 2년이 흘렀고, 2019년 Google I/O에서는 완전한 메인 언어로써 자리매김했음을 공식화했다.

GDG 부산에서 발표한 내용을 토대로 어떠한 변화가 있었는지 정리해보려고 한다.

 

GDG 부산 발표자료

 

2016년에 시작한 코틀린

2016년부터 학습한 Kotlin 관련 History를 간략화해본 그림이다.

image_01
History

처음 해본 코틀린 프로젝트

먼저 필자는 2016년에 Kotlin 정식 버전인 1.0을 시작으로 처음 학습했었고, 처음 시작한 프로젝트에 아래와 같이 흔적이 남아있다.

https://github.com/taehwandev/KotlinPhotoSample/blob/master/build.gradle

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.4"

본 프로젝트는 Flickr SDK 사용하고 있고, 화면별로 아래와 같은 구성을 가지고 있다.

  • 메인 화면 : Flickr 최근 목록을 불러온다.
  • 상세 화면 : 특정 사진의 확대 화면을 구성하며, 간단한 제목, 내용 등을 보여준다.

처음 Kotlin 학습으로 만들어본 프로젝트이며, 이미 알고 있던 기술과 새로운 기술들을 모두 조합하여 구성하였는데, 다음과 같은 SDK를 함께 사용하였다. 현재는 아주 흔하게 사용하는 기술들이지만 Kotlin을 처음 학습하면서 익힌 기술들이 포함되어있다.

실제 코드는 Kotlin 이긴 하지만 Java스럽게 작성한 코드들이 많았는데, Kotlin 기본 문법과 Android Studio에서 제공하는 Java to Kotlin Convert를 활용하여 작업하였다.

유데미 강의

우연한 기회로 온라인 강의를 찍게 되었다. 코틀린 학습을 한참 하고 있었는데, 더 빠르게 할 수 있는 방법이기도 했다. 남에게 설명하려면 좀 더 많은 공부가 필요하기에 좋은 기회였다. 결국 이로 인해 블로고 포스팅을 더 많이 할 수 있었고, 강의도 만들 수 있었다.

지금은 처음에 찍었던 영상은 공개로 돌려두었고, 이후 영상은 유지 중에 있다.

실제 적용 사례

회사 프로젝트에는 2017년 Google I/O 이후에 적용할 기회가 생겼었고, 이를 적용하였다. 자세한 내용은 요기요 블로그에서 확인 가능하다.

 

Kotlin History

Kotlin History를 대략 정리해보았다. 모든 내용을 포함하지는 않고, 일부 주요 내용을 포함하였다.

image_02
Kotlin History

 

구글의 Kotlin 지원

구글에서 Kotlin과 관련한 제공하는 부분을 간단하게 정리한다.

 

Google에서 공식 언어 지정 이후

코틀린은 2017년 구글에서 정식 언어로 채택하였고, Android Studio 3.0 버전부터 정식 지원하기 시작했다. 처음에는 구글 라이브러리 중 KTX 라이브러리에서 Kotlin을 제공하기 시작했다.

KTX 라이브러리에는 다음을 포함한다.

  • Extension functions
  • Extension properties
  • Lambdas
  • Named parameters
  • Parameter default values

결국 Kotlin을 아주 잘 활용할 수 있도록 확장 함수 형태의 코드를 제공하고 있는데, 다음과 같이 사용하는데

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

KTX 라이브러리를 통해 다음과 같이 활용하는 게 가능하다.

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

눈에 보이는 코드는 없지만 위에 apply 하는 것과 동일한 코드이다.

2019 Google I/O 이후

2019 Google I/O에서 Kotlin first로 선언했다. 이전에도 같은 용어를 사용했지만, 이젠 완전히 kotlin을 메인 언어로 지정하였다. 자바도 지원하지만 코틀린을 메인으로 지원하겠다는 의미이다.

이미 모든 문서에는 Kotlin 샘플이 먼저 노출되고 있고, Develop Android apps with Kotlin 문서를 통해 Kotlin 관련 샘플 프로젝트, 강의 등의 내용을 노출하고 있어 더 빠르게 더 많은 정보로 Kotlin 학습이 가능해졌다.

Coroutines 지원

2019년부터는 Coroutines에 대한 지원도 한다. Coroutine scope을 포함하는 ViewModelScope, LifecycleScope, liveData에서 사용할 수 있도록 Architecture components에서 제공하고 있다.

이 3 개의 라이브러리는 각각의 버전을 참고하여 추가해야 한다.

ViewModelScope, use androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01 or higher.
LifecycleScope, use androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01 or higher.
liveData, use androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01 or higher.

ViewModelScope

Coroutine을 사용하기 위해서는 CoroutineScope을 사용해야 한다. 이런 CoroutineScope을 좀 더 사용하기 편하게 하기 위해서 구글에서 만든 AAC-ViewModel에 CoroutineScope을 추가하여 확장하는 코드를 제공하는 것이다.

내부 코드를 살짝 보면 아래와 같이 생겼다. ViewModel을 확장하여 viewModelScope이라는 Extension properties을 만들어두었다.

val ViewModel.viewModelScope: CoroutineScope
        get() {
            val scope: CoroutineScope? = this.getTag(JOB_KEY)
            if (scope != null) {
                return scope
            }
            return setTagIfAbsent(JOB_KEY,
                CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main))
        }

internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context

    override fun close() {
        coroutineContext.cancel()
    }
}

그리고 아래와 같이 사용하도록 가이드하고 있는데, ViewModel을 상속받는 class에서 viewModelScope을 통해 launch 형태로 사용하는 게 가능하다.

class MyViewModel: ViewModel() {
    init {
        viewModelScope.launch {
            // Coroutine that will be canceled when the ViewModel is cleared.
        }
    }
}

좀 더 편하게 쓰려면

구글에서 만든 건 매번 viewModelScope을 이용하여 초기화해야 한다. 조금 귀찮아지긴 한다. 그래서 다음과 같은 형태로 새로운 ViewModelScope을 초기화하고, 이를 활용할 수 있다.

abstract class CoroutineScopeViewModel : ViewModel(), CoroutineScope {

    private val job = SupervisorJob()

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main
}

실제 사용은 구글 보다 더 편하게 사용하는 게 가능하다.

class TestViewModel : CoroutineScopeViewModel() {

    init {
        launch {
            // Coroutine that will be canceled when the ViewModel is cleared.
        }
    }
}

다만 이 방법은 BaseViewModel의 형태가 코틀린이 가능해야 한다. 아직 구글에서는 메인 라이브러리에 Kotlin을 적용하지는 않고 있고, 추후에 완전히 Kotlin 라이브러리를 배포한다면 위와 같은 형태로 제공이 가능해진다.

LifecycleScope

Lifecycle에서도 CoroutineScope을 제공한다. launch는 UI Thread로 동작하도록 작업되어서 UI 코드 처리가 가능해지는 것이다.

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

Use coroutines with LiveData

LiveData에서도 CoroutineScope을 제공하고, 다음과 같이 사용하는 게 가능하다.

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

그래서

아직까지는 KTX 라이브러리를 통해 Kotlin 확장 형태로 제공하는 것이다. 그래서 깔끔한 방법은 아니다. 결국 완전한 Kotlin 라이브러리를 제공하게 되어야 좀 더 좋은 방법의 접근이 가능해지게 될 것 같다. 아직은 시간이 필요하다.

 

Kotlin으로 변환 중인 라이브러리들

Google I/O 2019 이전에도 Kotlin으로 변환하는 오픈 라이브러리들이 많았다. 그중 우리가 많이 사용하는 라이브러리인 OkHttp는 열심히 Kotlin으로 코드를 변환하고 있음을 알려주었고, 이미 3.x 마지막 버전과 4.x 버전에서 Kotlin을 적용하고 있다.

Kotlin으로 빌드 한 프로젝트는 Kotlin dependencies를 추가하지 않으면 동작하지 않는다. 결국 Java로만 돌아가던 프로젝트에서도 Kotlin 라이브러리를 사용하기 위해서는 Kotlin dependencies을 추가해주어야 사용이 가능하다.

OkHttp의 경우 Java 59.1%, Kotlin 40.8%로 작업되었고, minSdk 21 이상부터 제공하도록 수정하였다.

JakeWharton이 주도하고 있는 RxBinding의 경우에도 이미 Kotlin 작성률이 54.1%에 달한다.

 

마무리

발표를 위해 정리한 내용이다. 앞으로 안드로이드 개발에서는 Kotlin은 필수가 될 것이다. 아직은 50%의 사용자가 Kotlin을 포함한 앱을 배포 중이지만 그 수치는 더 빠르게 올라갈 것으로 보인다. 뭐 단순하게 보면 Kotlin dependencies 추가만으로도 Kotlin 점유율은 높아진다.

다만 Java에서 Kotlin 활용은 깔끔하지는 않고, 지저분하긴 하다. 깔끔하게 지원하길 원한다면 결국 Kotlin을 사용해야 한다. 열심히 코틀린 공부를 하길 바란다!