Google for Mobile I/O RECAP 2018 (07)

07. Developer. Kotlin으로 코딩 시작하기

  • 발표자 : Hadi Hariri (VP of Developer Advocacy, Jetbrains)
  • 세션설명 : 한 번도 사용해보지 않은 개발자는 있어도, 한 번만 사용해 본 개발자는 없다! 사용해본 개발자의 95%가 높은 만족도를 보였다는 Kotlin! 작년 안드로이드 공식 언어로 채택된 이후 매년 빠르게 성장하고 있는 Kotlin을 시작해보세요. Google I/O에서 Kotlin을 발표했던 Jetbrain의 Hadi Hariri가 한국 개발자를 위해 직접 소개합니다.

코틀린 지식이 없는 상태에서 단편적인 키워드들로 정리한 세션이라 샘플코드 등 임의로 넣은 부분이 많습니다.

Kotlin 시작시 Android Studio의 Java to Kotlin 메뉴에 의존하지 말 것.

Property & Field

Kotlin은 필드는 없고 프로퍼티만 사용함.

참고 : https://kotlinlang.org/docs/reference/properties.html#backing-fields

Fields cannot be declared directly in Kotlin classes.

  • field: A data member of a class. Unless specified otherwise, a field is not static. - 클래스의 데이터 멤버. 특별히 언급되지 않았다면 field는 정적이지 않다.
  • property: Characteristics of an object that users can set, such as the color of a window - 윈도우의 색과 같이, 사용자가 설정할 수 있는 객체의 특성

Delegated Properties

참고 : https://kotlinlang.org/docs/reference/delegated-properties.html

  • lazy properties : 첫 번째 액세스시에만 값이 계산되어 저장됨.

    val lazyValue: String by lazy {
        println("computed!")
        "Hello"
    }
    
    fun main(args: Array<String>) {
        println(lazyValue)
        println(lazyValue)
    }
    This example prints:
    
    computed!
    Hello
    Hello
  • observable properties : 리스너는 속성 변경에 대해 알림을 받음.

    import kotlin.properties.Delegates
    
    class User {
        var name: String by Delegates.observable("<no name>") {
            prop, old, new ->
            println("$old -> $new")
        }
    }
    
    fun main(args: Array<String>) {
        val user = User()
        user.name = "first"
        user.name = "second"
    }
    This example prints:
    
    <no name> -> first
    first -> second
  • 맵에 여러 필드를 대신해 프로퍼티를 저장함.

    class User(val map: Map<String, Any?>) {
        val name: String by map
        val age: Int     by map
    }
    ...
    val user = User(mapOf(
        "name" to "John Doe",
        "age"  to 25
    ))
    ...
    println(user.name) // Prints "John Doe"
    println(user.age)  // Prints 25

Standard Library (Built-in)

lazy, vetoable 등 제공함.

funtion expression

참고 : https://kotlinlang.org/docs/reference/basic-syntax.html#defining-functions

// basic
fun sum(a: Int, b: Int): Int {
    return a + b
}

// expression
fun sum(a: Int, b: Int) = a + b

when expression

참고 : https://kotlinlang.org/docs/reference/basic-syntax.html#using-when-expression

https://kotlinlang.org/docs/reference/control-flow.html#when-expression

fun describe(obj: Any): String =
when (obj) {
    1          -> "One"
    "Hello"    -> "Greeting"
    is Long    -> "Long"
    !is String -> "Not a string"
    else       -> "Unknown"
}

exception expression

참고 : https://kotlinlang.org/docs/reference/exceptions.html

// basic
try {
    // some code
}
catch (e: SomeException) {
    // handler
}
finally {
    // optional finally block
}

// expression
val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }

Elvis operator

참고 : https://kotlinlang.org/docs/reference/null-safety.html

// basic
val l: Int = if (b != null) b.length else -1

// Elvis operator
val l = b?.length ?: -1

// Elvis operator (Exception)
val name = node.getName() ?: throw IllegalArgumentException("name expected")

Collections

sortWith

참고 : https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sort-with.html?q=sortwithc&p=0

data class Product(val name: String, val price: Double /*USD*/)
...
fun main(args : Array<String>){
	val products = arrayOf(Product("iPhone 8 Plus 64G", 850.00),
							Product("iPhone 8 Plus 256G", 1100.00),
							Product("Apple iPod touch 16GB", 246.00),
							Product("Apple iPod Nano 16GB", 234.75),
							Product("iPad Pro 9.7-inch 32 GB", 474.98),
							Product("iPad Pro 9.7-inch 128G", 574.99),
							Product("Apple 42mm Smart Watch", 284.93))
		
	products.sortWith(object: Comparator<Product>{
								override fun compare(p1: Product, p2: Product): Int = when {
													p1.price > p2.price -> 1
													p1.price == p2.price -> 0
													else -> -1
												}
					  })
}

map

참고 : https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html

var strCustList = customerList.map { it -> if(it!=null) "${it.name} lives at street ${it.address.street}" else null }
strCustList.forEach{println(it)}

mapNotNull

참고 : https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-not-null.html

publicp  inline fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R>

Null declare (?) 하지 말 것.

참고 : https://kotlinlang.org/docs/reference/basic-syntax.html#using-nullable-values-and-checking-for-null

Java를 위해서 만들어진 것.

In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references). For example, a regular variable of type String can not hold null:

https://kotlinlang.org/docs/reference/null-safety.html

To perform a certain operation only for non-null values, you can use the safe call operator together with let:

If you have a collection of elements of a nullable type and want to filter non-null elements, you can do so by using filterNotNull:

Semicolons

참고 : http://kotlinlang.org/docs/reference/grammar.html#semicolons

Kotlin provides "semicolon inference": syntactically, subsentences (e.g., statements, declarations etc) are separated by the pseudo-token SEMI, which stands for "semicolon or newline". In most cases, there's no need for semicolons in Kotlin code.

Inline Functions

참고 : https://kotlinlang.org/docs/reference/inline-functions.html

https://blog.uzuki.live/advanced-kotlin-inline-functions-1-basic/

https://blog.uzuki.live/inline-functions-2-local-return/

고차 함수(higher-order functions) 사용시 특정 런타임에서 패널티가 부과되며, 메모리 할당과 가상 호출은 런타임 오버헤드를 초래한다고 함.

이런 종류의 오버헤드는 람다 식을 inlining 함으로써 제거될 수 있음.

람다 사용시에만 inline 사용이 가능하며 퍼포먼스 개선이 가능하다.

Local Return 문에도 사용됨.

Functional Programming

return 타입을 명시해야 함.

fun Division(a: Int, b: Int): Int {
    return DivisionVaild(result)
    //return DivisionInvaild(result)
}

fun DivisionVaild(val result: Int)
fun DivisionInvaild(val result: String)

Sealed Classes

참고 : https://kotlinlang.org/docs/reference/sealed-classes.html

Sealed Class와 서브클래스는 같은 파일에 선언되어야 함.

Sealed Class는 abstract Class임. 직접 인스턴스화 할수 없고 abstract 멤버는 가질수 있음.

non-private constructors를 가지면 안됨.

주로 when 표현식에서 유용함.

sealed class Expr {
    data class Const(val number: Double) : Expr()
    data class Sum(val e1: Expr, val e2: Expr) : Expr()
	object NotANumber : Expr()
}
fun eval(expr: Expr): Double = when(expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
    // the `else` clause is not required because we've covered all the cases
}

Q&A

시간 관계상 생략

Google for Mobile I/O RECAP 2018 (06)

06. Developer. 빠르고 세련된 Android 개발 - Android Jetpack & Android Studio

  • 발표자 : 김태호 (Mobile Apps Technical Specialist, Online Partnership Group, Google)

  • 세션설명 : 견고하고 현대적인 안드로이드 애플리케이션을 만드려면 어떻게 해야할까요? 세련되고 빠른 Android 앱을 만들기 위한 컴포넌트, 도구 및 지침들을 담고 있는 Android Jetpack과 Android Studio를 소개합니다.

Android Studio

Layout Inspector

참고 : https://developer.android.com/studio/debug/layout-inspector?hl=ko

Profile

참고 :

​ CPU : https://developer.android.com/studio/profile/cpu-profiler?hl=ko

​ Memory : https://developer.android.com/studio/profile/memory-profiler?hl=ko

​ Network : https://developer.android.com/studio/profile/network-profiler?hl=ko

Runtime

  • Dalvik : 앱 Size가 중요하고, Heap Fragment 등의 이슈가 있음.
  • ART : Performance 에 최적화

Language

Java, Kotlin 사용하며, 부분적인 Kotlin 개발이 가능함. Kotlin Lint 체크 지원.

Library & API

  • AbsoluteLayout : 사용하지 말 것. 강조. 또 강조. 또 또 강조.
  • LinearLayout : 간단한 경우 사용.
  • FameLayout : 역시 간단히 사용.
  • GridLayout : 권장하지 않음.
  • RelativeLayout : 사용에 대한 비용이 비쌈.
  • ConstraintLayout : 권장하며 2.0 버전 나올 예정.

AdapterView

기존 ListView, GridView는 뷰홀더 패턴 직접 작성 등 처리 복잡하고 어려움.

RecyclerView가 다양한 레이아웃을 제공하며 사용하기 좋음.

Fragment

참고 : https://developer.android.com/reference/android/app/Fragment

This class was deprecated in API level 28. Use the Support Library Fragment for consistent behavior across all devices and access to Lifecycle.

Support Library에 있는 Fragment 사용 권장

  • android.app.Fragment
  • android.support.v4.app.Fragment (권장)

Activities

가능하다면 싱글 액티비티 권장

Architecture

참고 : https://developer.android.com/topic/libraries/architecture/

기존에는 권장하는 부분이 없었음. 현재는 AAC(Android Architecture Components) 로 가이드 제공함.(필수는 아님)

Life Cycle

참고 : https://developer.android.com/topic/libraries/architecture/lifecycle

Callback 처리 등으로 액티비티나 프래그먼트가 heavy 해짐. AAC 에서 액티비티와 독립적으로 Life Cycle을 제공함.

Views and Data

참고 : https://developer.android.com/topic/libraries/architecture/viewmodel

ViewModel이 처리하며, 인스턴스만 Activity에서 관리

Data

참고 : https://developer.android.com/topic/libraries/architecture/room

Room 등에서 지원함.

Android Jetpack

참고 :

https://developer.android.com/jetpack/

https://android-developers.googleblog.com/2018/05/use-android-jetpack-to-accelerate-your.html

Guidance

Android X

참고 :

https://developer.android.com/topic/libraries/support-library/refactor

https://android-developers.googleblog.com/2018/05/hello-world-androidx.html

기존 Support Library (android.support.*)와 AAC(android.arch.*)를 AndroidX(androidx.*)로 패키지명 교체.

버전은 1.0.0으로 리셋되며 -v4, -v7 같은 네이밍 제거됨.

OldNew
android.support.**androidx.@
android.databinding.**androidx.databinding.@
android.design.**com.google.android.material.@
android.support.test.**(in a future release) androidx.test.@
android.arch.**androidx.@
android.arch.persistence.room.**androidx.room.@
android.arch.persistence.**androidx.sqlite.@

Migration to Android X

Android Studio Canary 14 버전으로 Refactor 메뉴의 Refactor to AndroidX... 메뉴로 실행

그 외

Q&A

시간 관계상 생략

Google for Mobile I/O RECAP 2018 (05)

05. Developer. 새로운 모듈 Android App Bundle로 앱 개발하기

  • 발표자 :

    Phil Adams (Senior UX Researcher) Tom Dobek (Software Engineer, Google)

  • 세션설명 : Android App Bundle은 크기가 작은 앱으로도 우수한 사용 환경을 간편하게 제공할 수 있도록 도와주는 새로운 앱 모델입니다. 앱 크기를 대폭 줄이고 Dynamic Delivery를 통해 유저들이 앱을 더 빠르게 다운로드할 수 있도록 하는 방법을 소개합니다.

참고 : https://developer.android.com/guide/app-bundle/

https://medium.com/mindorks/android-app-bundle-aab-98de6dad8ba8

https://medium.com/mindorks/android-app-bundle-part-2-bundletool-6705b50bea4c

App Bundle이 가능하게 하는 2가지 기능

  • Dynamic delivery system
  • Modular App development

.aab 내부

  • AndroidManifest.xml가 apk에서는 바이너리 형식이지만 aab에서는 프로토콜 버퍼 형식.

  • aab는 내부에 dex 폴더가 따로 있음.

  • aab의 resources.pb는 apk의 resources.arac에 해당하는 파일로 역시 프로토콜 버퍼 형식.

  • resources table, assets table은 앱의 File Targeting을 설명함.

    예) assets/<name>#<key>_#<value>/...

Dynamic Delivery 의 기본 구성요소는 Split APK 매커니즘. (Android 5.0 Lollipop 이상)

Split APK는 일반 APK와 유사하지만 Android 플랫폼은 설치된 여러 개의 분리된 APK를 하나의 앱으로 취급할 수 있음.

App Bundle을 위한 Split 기능은 아래와 같이 사용 가능함.

Split APK의 종류

Base APK

모든 APK가 액세스할 수 있는 코드와 리소스 포함하여 앱의 기본기능 제공. 앱 다운로드시 설치되는 첫 번째 APK

Configuration APKs

각 APK에는 특정 화면 밀도, CPU 아키텍처, 언어에 대한 기본 라이브러리 및 리소스를 포함. 기기가 Base APK 또는 Dynamic feature APK 다운로드시 필요한 라이브러리와 리소스만 다운로드 됨.

Dynamic feature APKs

각 APK에는 앱 설치시 필요하지 않지만 나중에 다운로드하여 설치할 수 있는 코드와 리소스가 포함되어 있음.

Average Savings

App Bundle을 통해서 평균 20% 이상의 앱 용량을 절감함.

Publishing App Bundle

App Bundle을 만든 후 signing 하여 Google Play에 업로드.

App Bundle은 기기에 APK를 배포할 수 없는 대신 하나의 빌드 아티팩트에 모든 앱의 컴파일된 코드와 리소스를 포함하는 새로운 업로드 형태임.

signing된 App Bundle을 업로드하면 Google Play는 앱의 APK를 만들고 서명한 후 Dynamic Delivery를 통해 사용자에게 제공하는 데 필요한 모든 것을 제공함.

Publishing API에서도 App Bundle 지원함.

Internal Test Track을 사용하여 테스트.

bundletool

참고 : https://github.com/google/bundletool

App Bundle 을 로컬에서 테스트할 때 사용.

  • Android App Bundle 빌드
  • APK archive 생성
  • APK 추출
  • APK 설치
  • 장치 사양 추출

SplitInstallManager

참고 : https://developer.android.com/guide/app-bundle/playcore

Q&A

Q : 사용자가 설치 후 언어 변경시 앱을 재설치해야 하나?

A : Split App만 설치하면 됨.

Q : assets 타켓팅시 불필요한 파일 포함되는데 개선 여부는?

A : 타켓팅을 상세히 해서 하면 됨.

Q : 앱 수정시 앱 번들 모두 업데이트해야 하나?

A : 그렇다.

Q : 베이스 외 모듈 배포 가능하나?

A : On Demand 버전은 따로 배포가 안됨.

Q : 앱번들을 위한 최소 버전은?

A : Pre L도 지원함으로 따로 최소 버전은 없음.

Q : 모듈화에 대해 자세한 설명이나 사례는?

A : 게임에서 레벨에 따라 별도 다운로드 제공.

Q : 앱 번들 기기 지원 관련 이슈는?

A : 현재는 없음.



+ Recent posts