기존에는 그냥 연습용 앱이어서 해상도 별로 이미지를 생각하지 않고 drawable 에 다 때려 넣었다.

그러다보니 여러명에서 같이 하는 앱개발의 경우에, 각기 다른 Android Device 를 가지고 있어서, OutOfMemory  error 가 나는 경우가 많았다.

그래서 찾아봤는데 아래 사이트에서 각 해상도별 이미지를 생성 해준다.

https://romannurik.github.io/AndroidAssetStudio/nine-patches.html#&sourceDensity=320&name=example

 

Android Asset Studio - Simple nine-patch generator

Drag or select a source graphic to get started.

romannurik.github.io

 

생성된 이미지를 아래와 같이 적용해주기만 하면 된다.

splash_logo.png

 

그리고 불러다 쓸때는 기존에 @drawble/splash_logo 가 아닌 @mipmap/splash_logo 라고 해주면, 알아서 돌아가는 device 에 맞게 이미지를 로드 해준다. 

<ImageView
    android:id="@+id/splash_img"
    android:layout_width="0dp"
    android:layout_height="290dp"
    android:scaleType="fitCenter"
    android:contentDescription="@string/contentDescription_img"
    app:layout_constraintWidth_percent="0.7"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.276"
    app:srcCompat="@mipmap/splash_logo" />

 

굿굿 

 

Kotlin에서는 Range expression 을 통해서 개발자들이 편하게 사용할 수 있도록 해줍니다.

 

가장 흔하게 if 문이나 for문에서 사용될 수 있습니다.

".." operator 를 갖는 rangeTo 함수로 표현합니다.

아래는 C / JAVA 언어의 if (i>=1 && i<= 10) 조건문과 같은 의미를 가집니다.

if (i in 1..10) { // equivalent of 1 <= i && i <= 10
    println(i)
}

아래와 같이 반복문에서도 사용합니다

이때 1..4 와 같이 커지는 순서로 for문을 동작 시키게 되는데요

아래와 같이 4..1 이 되면 아무것도 수행되지 않게 됩니다.

for (i in 1..4) print(i) // prints "1234"

for (i in 4..1) print(i) // prints nothing

그렇다면 C언어에서처럼 i값을 점점 작아지게 하고 싶으면 어떻게 하면 될까요?

C언어에서 for (int i = 4 ; i > 0 ; i --) 와 같이 사용되는 반복문을

Kotlin에서는 downTo() 함수를 통해 아래와 같이 표현할 수 있습니다.

for (i in 4 downTo 1) print(i) // prints "4321"

 

또한 step을 사용하여 일정한 간격으로 i를 증가시킬 수도 있고,

downTo와 step을 함께 사용하여 역순으로 일정간격으로 i를 감소시킬 수도 있습니다.

첫번째 for문은 1부터 4까지 2씩 건너뛰므로, 1과 3이 출력됩니다.

두번째 for문은 4부터 1까지 2씩 건너뛰므로, 4와 2가 출력됩니다.

for (i in 1..4 step 2) print(i) // prints "13"

for (i in 4 downTo 1 step 2) print(i) // prints "42"

 

until 함수를 사용하여 범위를 결정할 수도 있습니다.

(아래의 식에서 i는 1에서 9까지만 수행합니다. 10은 포함되지 않습니다.)

C언어에서보다는 쉽고 다양하게 표현할 수 있지만,

처음 접한다면 익숙한 C언어의 표현을 바꿔서 하기에 좀 불편하기도 할 것 같아요.

for (i in 1 until 10) { // i in [1, 10), 10 is excluded
     println(i)
}

 

마지막으로 last 함수를 사용하여 마지막 i 값을 확인할 수 있습니다.

(1..12 step 2).last == 11  // progression with values [1, 3, 5, 7, 9, 11]
(1..12 step 3).last == 10  // progression with values [1, 4, 7, 10]
(1..12 step 4).last == 9   // progression with values [1, 5, 9]

 

 

 

이번 포스팅에서는 Kotline 의 기본 제어문(반복문/조건문) 사용법을 알아보도록 하겠습니다.

모든 언어들이 비슷하기 때문에 하나의 언어만 잘 알아두면 나머지 언어의 문법도 금방금방 익힐 수 있는 것 같습니다.

Kotline 의 제어문도 다른 언어들과 비슷 하지만, 함축적으로 사용되는 부분이 있어 다른 언어들과는 다르게 Kotline 의 문법을 모르면 잘 알아보기가 힘들게 되어 있는 부분도 있습니다.

익숙해 지면 다른 언어들보다 편할것이라는 생각도 드네요. ^^

 

1. If 문

Kotline 에서 if 문은 Expression 입니다. 즉, value 를 return 합니다. if 문 자체로 기존의 3항 연산자의 역할을 대체하기 때문에 더이상 삼항 연산자는 사용되지 않습니다. (조건 ? true : false)

기존 우리는 if 문을 아래와 같이 사용했습니다.

max 에 a 변수를 넣고, 만약 a 보다 b 가 크다면 max 변수에 b 의 값을 넣는 코드입니다.

// Traditional usage 
var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

 Kotline 에서는 위의 if 문을 아래와 같이 간단하게 사용할 수 있습니다.

// As expression 
val max = if (a > b) a else b

즉, " if (a>b) a else b " 구문 자체가 a 혹은 b 의 값을 return 하기 때문에, max 변수에 바로 이 값을 대입할 수 있습니다.

만약, if 문 자체에 블럭이 포함되어야 한다면 위 구문은 아래와 같이 사용할 수 있습니다.

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

위의 경우 블럭의 끝에 쓰여진 값이 return 되는 값이 됩니다.

 

2. When

When 은 일반 언어에서 사용되던 Switch 문을 대체합니다.

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // Note the block
        print("x is neither 1 nor 2")
    }
}

When 옆에 쓰여진 x 에 값이, 블럭 안의 조건에 충족이 될 때 까지 모든 인수를 순차적으로 검사 합니다.

아무 조건에도 충족되지 않으면 else 분기문으로 들어가게 되고, Switch 문의 default 문은 필수가 아니지만, When 의 else 문은 필수로 들어가야 합니다.

많은 경우가 동일한 방식으로 처리되어야 하는 경우에는 . (콤마) 를 사용하여 조건을 추가할 수 있습니다.

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

각 조건의 경우에는 위와 같이 특정 상수 값 (0, 1) 이 올 수도 있지만, 함수가 올 수도 있습니다.

when (x) {
    parseInt(s) -> print("s encodes x")
    else -> print("s does not encode x")
}

위의 경우에는 x 와 parseInt() 에서 return 되는 값과 일치하게 되면 "s encodes x" 를 출력할 것입니다.

그리고 in 키워드를 사용하여 특정 값의 범위를 지정 할 수도 있습니다.

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

in 1..10 은 1<= x <=10 의 범위를 의미 합니다. Range 에 대해서는 'https://kotlinlang.org/docs/reference/ranges.html' 를 참고해 보세요 .

마지막으로 when 을 사용할 때 인수를 생략할 수 있습니다.

인수를 생략하게 되면 분기 조건은 단순히 bool 식이 되고, 해당 조건이 참일 때 분기문이 실행 됩니다.

아래의 경우에서는 x 가 홀수 일 경우 "x is odd", 짝수일 경우 'x is even" 둘다 아닐 경우에 "x is funny" 가 출력 됩니다.

when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

 

3. For Loops

for loop 는 비교적 기존에 사용하던 for 문과 크게 다르지 않습니다. iterator 를 제공하는 모든 것들을 반복할 수 있습니다.

아래 예제에서는 item 에 collection 에 있는 모든 값들이 하나씩 대입이 되면서 반복 하게 됩니다.

for (item in collection) print(item)

배열이나 리스트를 반복할 경우에 index 를 사용하고 싶다면 indices를 사용 합니다.

for (i in array.indices) {
    print(array[i])
}

혹은 withIndex' fun 을 사용해서 index 와 value 를 return 받아 for문을 돌릴 수도 있습니다.

for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

 

4. While Loops

while 문과 do.. while 문은 java 와 완전히 동일합니다.

아래의 예제에서 do 블록 안에 정의한 멤버변수 y 는 while 의 조건 식에서 참조할 수 있습니다.

while (x > 0) {
    x--
}

do {
    val y = retrieveData()
} while (y != null) // y is visible here!

 

여기까지 Kotline 의 if, when, for, while 제어문 사용법에 대해 간단히 알아보았습니다.

기본 문법이기 때문에 잘 익혀두면 Kotline 으로 코딩하는데 많은 도움이 될 것입니다.

'Language > Kotlin' 카테고리의 다른 글

[Kotlin] Range 사용하기  (0) 2018.01.25
[Kotlin] 함수 사용하기  (0) 2017.12.28
[Kotlin] Class 두번째 이야기  (0) 2017.12.22
[Kotlin] Class 사용하기  (0) 2017.12.15
안드로이드 공식 개발언어 Kotlin  (0) 2017.12.01

Kotlin 에서의 함수는 fun 키워드를 사용합니다.

fun double(x: Int):Int {
    return 2 * x
}

함수는 일반적으로 아래와 같이 부를 수 있습니다.

 

val result = double(2)

.(dot) 을 사용하여 멤버 함수를 부를 수도 있습니다.

 

Math().double()

 

Default Arguments

Parameter 의 전달은 name: type 과 같이 사용하며, default value 를 가질 수 있습니다. 인자가 전달되지 않으면 default value 가 값에 사용되며 불필요한 함수 오버로딩을 막을 수 있습니다.

checkCustomer("Gildong") 와 같이 필요한 인자만 사용하여 함수 호출이 가능합니다.

fun checkCustomer(name: String, phone: String = "NA", age: Int = 30){
    ...
}

checkCustomer("Gildong") // The default value phone = "NA" age = 30 is used

오버라이딩은 상위 메소드와 동일한 인자를 가지게 되므로, default value 를 사용하지 않을 때는 오버라이딩을 하여 default value 를 선언하지 않아야 합니다.

open class A {   open fun foo(i: Int = 10) {...}
}

class B: A(){
   override fun foo(i: Int) {...}   // no default value allowed
}

 

 

Name Arguments

함수를 호출할 때 parameter 의 이름을 사용하는데, 이를 Name Argument 라고 부릅니다.

fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char ' ') {
...
}

위와 같은 함수가 있을때 아래와 같이 호출 할 수 있습니다.(위에서 default value 에 대해 설명한 것을 참고하시면 됩니다.)

reformat(str)

default value 가 없다면 reformat(str, true, true, false, ' ') 라고 불러야 할 것입니다. Name Argument 는 좀더 읽기 쉽게 아래와 같이 표현할 수 있도록 해줍니다.

reformat(str,
        normalizeCase = true,
        upperCaseFirstLetter = true,
        divideByCamelHumps = false,
        wordSeparator = '_')

모든 parameter 를 전달하지 않고 아래와 같이 사용가능합니다.

reformat(str, wordSeparator = '_')

단, str 인자가 positional argument 라 부르는데, positional argument는 항상 Name argument 보다 앞에 있어야 합니다.

즉, f(1, y = 2)는 가능하지만 f(x = 1, 2) 는 불가능합니다.

 

Unit-returning Functions

함수에서 return 값이 불필요하다면 return type을 Unit 으로 선언할 수 있습니다. Unit 은 명시적으로 반환할 필요가 없습니다.

return Unit 이나 return 은 선택적으로 할 수 있습니다. 또한 Unit 은 생략 가능합니다.(반환값을 사용하지 않는다면 Unit 이 생략되어 있는것과 같습니다.)

fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there")
}

 

Single-Expression functions

함수가 한줄로 표현 가능하다면 괄호는 생략 가능합니다. 또한 반환값도 컴파일러에 의해 유추될 수 있다면 생략 가능합니다.

fun double(x: Int): Int = x * 2

fun double(x: Int) = x * 2

 

Variable number of arguments(Varargs)

함수의 매개 변수는 vararg modifier로 표시될 수 있습니다.

fun <T> asList(vararg ts: T): List<T> {
    val result = ArrayList<T>()
    for(t in ts) // ts is an Array
        result.add(t)
    return result
}

val list = asList(1, 2, 3)

asList 함수에서 T형의 vararg 매개 변수가 T의 배열로 표시됩니다. 하나의 매개 변수만 vararg로 표시 될 수 있습니다.

 

 

Kotlin 에서의 Class 사용에 대해서 알아보도록 하겠습니다.

Java 와의 호환성이 Kotlin 의 큰 장점으로 부곽되는 만큼 Java 와 비교하게 되는 부분이 있습니다.

 

Kotlin 에서 Class는 Java와 같이 아래처럼 사용합니다.

class Person{ }

그러나 Java 와 다르게 Body 가 없이 아래와 같이 사용될 수도 있습니다.

class Person

 

Kotlin에서는 primary constructor 과 하나 이상의 secondary constructor 를 가질 수 있습니다.

primary constructor 는 class 선언시 함께 가능합니다.

constructor 키워드는 생략 가능합니다.

annotation 이나 접근자(private, pubilc 등) 와 함께 사용되는 경우 생략할 수 없습니다.

class Person constructor(firstName: String) {

}
class Person(firstName: String) {

}

primary constructor

primary constructor 는 어떤 코드도 포함하지 않으므로 initializer block 을 사용하여 초기화 코드를 구현하면 됩니다.

constructor 가 불리면 객체 생성이 되면서 initializer block 이 불립니다.

primary constructor 의 parameter 는 class 내 어디서든(init 블럭이나 속성값 초기화) 사용 가능합니다.

class Person(name: String) {
    val nameInfo = "Name : $name".also(::println)

    init {
        println("First initializer block that prints ${name}")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

 

secondary constructor

constructor 키워드가 반드시 사용되어야 합니다.

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

primary constructor 가 있는 경우 모든 second constructor는 primary constructor 에게 위임해야 합니다. 동일 클래스 내에서 다른 생성자로의 위임은 this 키워드를 사용합니다.

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

initializer block의 코드는 primary constructor 의 일부가 된다. primary constructor 로의 위임은 secondary constructor 코드 실행 전에 실행되므로 모든 initializer block 의 코드는 가장 먼저 실행됩니다.

class Constructors {
    init {
        println("Init block")    // 먼저 실행됨
    }

    constructor(i: Int) {
        println("Constructor")   // 나중에 실행됨
    }
}

 

class의 instance 생성하기

class의 instance 를 생성하는데 JAVA에서는 new 키워드를 사용했다면, Kotlin 에서는 constructor 호출만 하면 됩니다.

val invoice = Invoice()

val customer = Customer("Joe Smith")

 

class 상속받기

Kotlin 에서 class 를 상속받기 위해서는 아래와 같이 사용할 수 있습니다.

C++과 같이 : 기호를 사용하는데 super class의 클래스명에 괄호기호가 붙는 점이 다르네요

물론 함수 override 도 아래와 같이 할 수 있습니다.

open annotation은 class로부터의 상속이 가능하다는 의미입니다. Kotlin에서는 모든 class가 default로 final 로 선언됩니다

open annotation을 사용하는 경우에만 상속이 가능합니다.

method 의 경우에도 open annotation이 있는 method 만 override 가능합니다.

open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
    override fun v() {}
}

변수의 경우 val 변수(Read only) 를 var 변수로 재정의 할 수 있지만, 반대는 안됩니다.

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

 

 

지난 2017년 5월 Google I/O 에서 Kotlin이 안드로이드의 공식 개발 언어로 발표되었습니다.

Kotlin 공식 사이트를 보면 아래와 같이 메인에서 소개하고 있습니다.

말 그대로 Java와 Android 에서 100% 호환가능하며 여러 platform 에서 동작하는 언어라고 정의하고 있는데요.

 

Kotlin은 Anroid Studio 개발사인 JetBrain 社 에서 만든 언어로 Kotlin/JVM, Kotlin/JS, Kotlin/Native 등 여러 환경에서 동작을 합니다.

Java 와 100% 호환이 되므로 Android의 API 들을 그대로 사용할 수 있고, Ant, Maven, Gradle과 같은 빌드 시스템을 사용할 수 있어 기존의 Android 개발자들이 낯설치 않게 사용 가능할 것이라 생각됩니다.

 

Java 코드를 Kotlin코드로 변환하는 도구를 제공하고 있으며, Java 로 개발하는 것보다 비약적으로 코드의 양이 줄어들고 여러 개발자들의 번거로움을 덜어줄 수 있도록 NullPointerException에 대한 안정성이 증가하였습니다.

 

Kotlin 에 대해 기본문법에 대해 좀더 알아보겠습니다.

 

1. Kotlin 은 문장 끝에 세미콜론이 없다.

C, C++, Java 많은 언어들이 세미콜론으로 문장의 끝을 알리는데요. Kotlin의 문장 끝에는 세미콜론이 없습니다.

한 줄에 여러 문장을 표현할 때만 세미콜론을 이용합니다.

 

2. 전역함수 사용이 가능하다

함수가 반드시 클래스 내에 있지 않습니다.

 

3. new 키워드 삭제

 

4. 함수 선언은 [접근지정자][inline][final] fun 함수명(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입) :반환형의 형태로 한다.

 

5. val과 var

val은 읽기전용 변수(final 개념) 이며 var는 읽기&쓰기가 가능한 변수를 뜻합니다.

변수선언과 동시에 초기화를 하면 타입을 알아서 추론하기 때문에 변수의 타입이 생략 가능합니다.

 

아래의 3개 sample 코드를 통해 1~5번까지의 문법 설명이 가능하다.

MainActivity.kt

class MainActivity : AppCompatActivity() {

   
override fun onCreate(savedInstanceState: Bundle?) {
       
super.onCreate(savedInstanceState)
        setContentView(R.layout.
activity_main)

        sayHello(
"GoodFortune")

       
val ck = ClassKotlin("GoodFortune");
       
val ck2 = ClassKotlin("GoodManner", "01055563262");
       
var ck3 = ClassKotlin("GoodMan", "01044778855", "ourhome")
    }
}
 

KotlinTest.kt

fun sayHello(who:String){
    val TAG: String = "KotlinTest"
    Log.d(TAG, "sayHello "+who)
}

ClassKotlin.kt

class ClassKotlin(var name: String, var phone: String="", var addr: String ="")
{

}

 

6. Nullable

Kotlin 의 가장 큰 장점 중 하나라고 할 수 있습니다. Kotlin에서는 NullPointException 이 발생하지 않는다고 하니 많은 분들이 반가워 할 것 같습니다.

Kotlin 에서는 변수에 null을 저장하고 싶으면 타입명 뒤에 "?"를 붙여 null을 가질 수 있는 변수임을 알려줍니다.

Nullable은 null을 가질 수 있는 변수 타입을 말합니다. (그렇지 않은 변수는 Non-Null 이라고 합니다)

Non-Null 변수인 경우 값이 null 이 아님을 보장할 수 있으므로 Null 체크가 필요없으며 NullPointerException도 발생하지 않습니다.

Nullable 변수에 대해서는 null 체크가 없으면 컴파일러에 의해 오류가 발생합니다.

아래 sample code 에서 checkphone 은 Nullable 변수이므로 checkphone.length 를 사용시 compile error 를 발생시킵니다.

class ClassKotlin(var name: String, var phone: String="", var addr: String ="")
{
    fun checkInformation(){
        var checkname: String = name
        var checkphone: String? = phone

        if ( checkname.length > 0 ) {   // OK
           
        }
       
        if ( checkphone.length > 0) {   // compile error
           
        }

    }
}

 

7. When 문

switch 문의 변형이라고도 볼 수 있는데요. switch-case 에서는 하나의 변수값에 대해 integer 형으로만 구분할 수 있는데 when 문은 아래와 같이 다양하게 사용될 수 있습니다.

when{
    name.equals("GoodFortune") -> Log.d(TAG, "GoodTortune")
    phone.length < 9 -> Log.d(TAG, "phone number is short")
}

 

간단한 문법에 대해서 알아보았는데, 다음번엔 Android Studio 3.0 에서 직접 사용하는 방법에 대해서도 알아보려고 합니다.

Android Studio 3.0 에서 JAVA 코드를 Kotlin으로 변환도 가능하다고 하네요^^

 

 

'Language > Kotlin' 카테고리의 다른 글

[Kotlin] Range 사용하기  (0) 2018.01.25
[Kotlin] if, when, for, while 제어문 사용하기  (0) 2018.01.04
[Kotlin] 함수 사용하기  (0) 2017.12.28
[Kotlin] Class 두번째 이야기  (0) 2017.12.22
[Kotlin] Class 사용하기  (0) 2017.12.15

+ Recent posts