포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 에외(Exception), Try, Catch, Finally, Toast


▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기

2018/03/15 - [Android_Kotlin] - [Android Kotlin] 문자열 템플릿(String Template) 사용법

2018/06/05 - [Android_Kotlin] - [Android Kotlin] 클래스, 프로퍼티, 커스텀 접근자 - 라디오 버튼(Radio Button)



코틀린의 예외처리는 자바와 비슷합니다. 


다른 점이 있다면 코틀린에서는 체크 예외 처리를 강제하지 않습니다. 개발자들이 예외를 잡지만 처리는 하지 않고 무시하는 코드로 작성을 흔하게 하기에 이를 고려하여 자바와는 다르게 강제하지 않은 것이 아닐까 생각합니다. 


이 역시 예제로 한번 살펴 보겠습니다.




1. 레이아웃

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Main1Activity.ExceptionActivity">

<EditText
android:hint="문자 입력시 예외처리"
android:id="@+id/edt_ex_str"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"
android:gravity="center"
android:background="@null"/>

<Button
android:id="@+id/btn_ex1"
android:text="Try Catch Finally 사용 예외처리"
android:layout_width="match_parent"
android:layout_height="50dp" />
<Button
android:id="@+id/btn_ex2"
android:text="Try를 식으로 예외처리"
android:layout_width="match_parent"
android:layout_height="50dp" />
<Button
android:id="@+id/btn_ex3"
android:text="Catch에서 값 반환"
android:layout_width="match_parent"
android:layout_height="50dp" />

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txt_ex_log"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:gravity="center"/>
</ScrollView>
</LinearLayout>





2. 소스

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.Toast
import com.kotlin_test.R
import kotlinx.android.synthetic.main.activity_exception.*
import java.io.BufferedReader
import java.io.StringReader

class ExceptionActivity : AppCompatActivity() {

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

btn_ex1.setOnClickListener {
txt_ex_log.setText("")

val reader = BufferedReader(StringReader(edt_ex_str.text.toString()))

txt_ex_log.setText(readNumber1(reader).toString())
}

btn_ex2.setOnClickListener {
txt_ex_log.setText("")

val reader = BufferedReader(StringReader(edt_ex_str.text.toString()))

readNumber2(reader)
}

btn_ex3.setOnClickListener {
txt_ex_log.setText("")

val reader = BufferedReader(StringReader(edt_ex_str.text.toString()))

readNumber3(reader)
}
}

// 자바와 동일한 방식의 Try
fun readNumber1(reader: BufferedReader): Int? {
try {
val line = reader.readLine() // 자바로 이 부분을 처리하기 위해선 체크 예외를 명시적으로 처리해야 한다.
// 하지만 코틀린에서는 함수가 던질 수 있는 예외를 명시할 필요가 없다. (throws IOException을 붙이지 않아도 된다.)
return Integer.parseInt(line)
}
catch (e: NumberFormatException) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show()
return null
}
finally {
reader.close()
}
}

// Try를 식으로 사용하기
fun readNumber2(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show()
return // 예외가 발생하면 return
}

txt_ex_log.setText(number)
}

// Catch에서 값 반환하기
fun readNumber3(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show()
null // 예외가 발생하면 null 값을 사용
}

txt_ex_log.setText(number.toString())
}
}



3. 실행 결과


포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 이터레이션(Iteration), For, In, Map, Collection


▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기

2018/03/15 - [Android_Kotlin] - [Android Kotlin] 문자열 템플릿(String Template) 사용법

2018/06/05 - [Android_Kotlin] - [Android Kotlin] 클래스, 프로퍼티, 커스텀 접근자 - 라디오 버튼(Radio Button)


코틀린에서의 이터레이션(Iteration)에 대해 알아보겠습니다.

코틀린에서의 이터레이션은 자바와 흡사합니다. 그중 while 루프는 자바와 동일하므로 이번 포스팅에 다루지 않습니다. while을 제외한 for, in, map, collection에 대해 예제로 사용법을 알아보겠습니다.


1. 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Main1Activity.ForInActivity">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="피즈버그 게임"
android:textSize="20dp"
android:textStyle="bold"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="10"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/rdo_direction"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="7"
android:orientation="horizontal"
android:gravity="center">
<RadioButton
android:id="@+id/rbtn_increase"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="증가"
android:paddingRight="20dp"/>
<RadioButton
android:id="@+id/rbtn_decrease"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="감소" />
</RadioGroup>
<EditText
android:id="@+id/edt_step"
android:hint="스텝 입력"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="3"
android:background="@null"
android:gravity="center"/>
</LinearLayout>

<Button
android:id="@+id/btn_for1"
android:text="실행"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="맵 이터레이션"
android:textSize="20dp"
android:textStyle="bold"/>
<Button
android:id="@+id/btn_for2"
android:text="실행"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="컬렉션 이터레이션"
android:textSize="20dp"
android:textStyle="bold"/>
<Button
android:id="@+id/btn_for3"
android:text="실행"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="컬렉션 이터레이션"
android:textSize="20dp"
android:textStyle="bold"/>
<EditText
android:id="@+id/edt_ins1"
android:hint="숫자 혹은 문자 입력"
android:layout_width="match_parent"
android:layout_height="50dp"
android:maxLength="1"
android:background="@null"
android:gravity="center"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="6"
android:orientation="horizontal">

<Button
android:id="@+id/btn_for4"
android:text="문자검사"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:textSize="20sp"/>

<Button
android:id="@+id/btn_for5"
android:text="숫자검사"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:textSize="20sp"/>

<Button
android:id="@+id/btn_for6"
android:text="When 사용"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:textSize="20sp"/>

</LinearLayout>

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txt_for_log"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:gravity="center"/>
</ScrollView>
</LinearLayout>





2. 소스

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.kotlin_test.R
import kotlinx.android.synthetic.main.activity_for_in.*
import java.util.*

class ForInActivity : AppCompatActivity() {

var log = ""

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

var increase = true

// Radio Button 리스너
rdo_direction.setOnCheckedChangeListener { radioGroup, i -> if(i == R.id.rbtn_increase) increase = true else increase = false }
// Radio Button 기본값 기정
rdo_direction.check(R.id.rbtn_increase)


// for ---------------------------------------------------------------------------------------------------------------------------
// 피즈버그 게임 실행 버튼
btn_for1.setOnClickListener {
log = ""
txt_for_log.setText("")

if(increase) {
// for 증가 (..)
if(edt_step.text.toString().equals("")) {
for (i in 1..100) {
log += fizzBuzz(i) + "\n"
}
} else {
val num = Integer.parseInt(edt_step.text.toString())

// step : 증가값 지
for (i in 1..100 step num) {
log += fizzBuzz(i) + "\n"
}
}

txt_for_log.setText(log)
} else {
// for 감소 (downTo)
if(edt_step.text.toString().equals("")) {
for (i in 100 downTo 1) {
log += fizzBuzz(i) + "\n"
}
} else {
val num = Integer.parseInt(edt_step.text.toString())

// for 감소 : downTo
for (i in 100 downTo 1 step num) {
log += fizzBuzz(i) + "\n"
}
}

txt_for_log.setText(log)
}
}

// 맵 이터레이션 실행 버튼
btn_for2.setOnClickListener {
log = ""
txt_for_log.setText("")

// 키에 대해 정렬하기 위해 TreeMap 사용
val binaryReps = TreeMap<Char, String>()

// 입력 - 맵에 값 셋팅
for (c in 'A'..'F') {
val binary = Integer.toBinaryString(c.toInt()) // 아스키(ASCII) 코드를 2진 표현으로 바꾼다.
binaryReps[c] = binary // java로 표현하면 binaryReps.put(c, binary)와 같다.
}

// 출력 - 맵 키(letter)와 값(binary)을 두 변수에 각각 대입한다.
for ((letter, binary) in binaryReps) {
log += ("$letter = $binary\n")
}

txt_for_log.setText(log)
}

// 컬렉션 이터레이션 실행 버튼
btn_for3.setOnClickListener {
log = ""
txt_for_log.setText("")

// 입력 - 컬렉션 인덱스(index)와 값(element)을 두 변수에 각각 대입한다.
var list = arrayListOf("10", "11", "1001")
for((index, element) in list.withIndex()) {
log += ("$index = $element\n")
}

txt_for_log.setText(log)
}



// in ---------------------------------------------------------------------------------------------------------------------------
// 문자검사 버튼
btn_for4.setOnClickListener {
log = ""
txt_for_log.setText("")

var str = edt_ins1.text.toString()

if(!str.equals("")) {
var c_arr: CharArray = str.toCharArray()

if (isLetter(c_arr[0])) {
txt_for_log.setText("문자 검사 : true")
} else {
txt_for_log.setText("문자 검사 : false")
}
}
}

// 숫자검사 버튼
btn_for5.setOnClickListener {
log = ""
txt_for_log.setText("")

var str = edt_ins1.text.toString()

if(!str.equals("")) {
var c_arr: CharArray = edt_ins1.text.toString().toCharArray()

if (isDigit(c_arr[0])) {
txt_for_log.setText("숫자 검사 : true")
} else {
txt_for_log.setText("숫자 검사 : false")
}
}
}

// WHEN사용 버튼
btn_for6.setOnClickListener {
log = ""
txt_for_log.setText("")

var str = edt_ins1.text.toString()

if(!str.equals("")) {
var c_arr: CharArray = edt_ins1.text.toString().toCharArray()

txt_for_log.setText(recognize(c_arr[0]))
}
}
}

// 피즈버즈 게임
fun fizzBuzz(i: Int) =
when {
i % 15 == 0 -> "FizzBuzz " // 15로 나눠서 떨어지면 FizzBuzz
i % 3 == 0 -> "Fizz " // 3으로 나눠서 떨어지면 Fizz
i % 5 == 0 -> "Buzz " // 5으로 나눠서 떨어지면 Buzz
else -> "$i "
}

// in을 사용해 값이 범위에 속하는지 검사하기 : 문자
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'

// in을 사용해 값이 범위에 속하는지 검사하기 : 숫자
fun isDigit(c: Char) = c in '0'..'9'

// !in을 사용해 값이 범위에 속하지 않는지 검사하기
fun isNotLetter(c: Char) = c !in 'a'..'z' || c !in 'A'..'Z'

// when에서 in 사용하기
// 문자열에 국한되지 않고 비교가 가능한 클래스(java.lang.Comparable 인터페이스가 구현된 클래스)라면 그 클래스의 인스턴스 객체를 사용해 범위를 만들 수 있다.
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "숫자"
in 'a'..'z', in 'A'..'Z' -> "문자"
else -> "I don't know…​"
}
}


3. 실행 결과




포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 스마트 캐스트(Smart Cast)


▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기

2018/03/15 - [Android_Kotlin] - [Android Kotlin] 문자열 템플릿(String Template) 사용법

2018/06/05 - [Android_Kotlin] - [Android Kotlin] 클래스, 프로퍼티, 커스텀 접근자 - 라디오 버튼(Radio Button)


이번엔 코틀린의 스마트 캐스트에 포스팅하겠습니다.


코틀린에서는 is를 사용해 타입검사를 합니다. 자바의 instanceof와 비슷합니다. 하지만 자바에서는 어떤 변수의 타입을 instanceof로 확인한 다음에는 그 타입에 속한 멤버에 접근하기 위해서는 명시적으로 변수 타입을 캐스팅해야 합니다. 하지만 코틀린에서는 프로그래머 대신 컴파일러가 캐스팅을 해줍니다.


즉, is로 검사하고 나면 굳이 변수를 원하는 타입으로 캐스팅하지 않아도 마치 처음부터 그 변수가 원하는 타입으로 선언된 것 처럼 사용할 수 있습니다. 이런 기능을 스마트 캐스트(Smart Cast)라고 부릅니다. 이제 아래 작성한 소스를 보시면 이해가 더 쉽게 되실 것입니다.




1. 레이아웃

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Activity.SmartCastActivity">

<TextView
android:text="산술식 : ( a + b ) + c"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="6">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="첫 번째 :"
android:gravity="center"/>
<EditText
android:id="@+id/edt_int_01"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="두 번째 :"
android:gravity="center"/>
<EditText
android:id="@+id/edt_int_02"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="세 번째 :"
android:gravity="center"/>
<EditText
android:id="@+id/edt_int_03"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"/>
</LinearLayout>
<Button
android:id="@+id/btn_cal1"
android:text="If 연쇄 계산하기"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>

<Button
android:id="@+id/btn_cal2"
android:text="값을 만들어내는 If 계산하기"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_cal3"
android:text="When 사용 계산하기"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_cal4"
android:text="When 블록 사용 계산하기"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"/>
<TextView
android:id="@+id/txt_cal_result"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"
android:gravity="center"/>
<TextView
android:id="@+id/txt_cal_log"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="21sp"
android:gravity="center"/>
</LinearLayout>





2. 소스

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.kotlin_test.R
import kotlinx.android.synthetic.main.activity_smart_cast.*

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

class SmartCastActivity : AppCompatActivity() {
var log: String = ""

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

btn_cal1.setOnClickListener {
txt_cal_log.setText("")

val num1: Num = Num(Integer.parseInt(edt_int_01.text.toString()))
val num2: Num = Num(Integer.parseInt(edt_int_02.text.toString()))
val num3: Num = Num(Integer.parseInt(edt_int_03.text.toString()))

val result: Int = eval1(Sum(Sum(num1, num2), num3))
txt_cal_result.setText("If 연쇄 : " + result.toString())
}

btn_cal2.setOnClickListener {
txt_cal_log.setText("")

val num1: Num = Num(Integer.parseInt(edt_int_01.text.toString()))
val num2: Num = Num(Integer.parseInt(edt_int_02.text.toString()))
val num3: Num = Num(Integer.parseInt(edt_int_03.text.toString()))

val result: Int = eval2(Sum(Sum(num1, num2), num3))
txt_cal_result.setText("If 식 : " + result.toString())
}

btn_cal3.setOnClickListener {
txt_cal_log.setText("")

val num1: Num = Num(Integer.parseInt(edt_int_01.text.toString()))
val num2: Num = Num(Integer.parseInt(edt_int_02.text.toString()))
val num3: Num = Num(Integer.parseInt(edt_int_03.text.toString()))

val result: Int = eval3(Sum(Sum(num1, num2), num3))
txt_cal_result.setText("When 사용 : " + result.toString())
}

btn_cal4.setOnClickListener {
log = ""
val num1: Num = Num(Integer.parseInt(edt_int_01.text.toString()))
val num2: Num = Num(Integer.parseInt(edt_int_02.text.toString()))
val num3: Num = Num(Integer.parseInt(edt_int_03.text.toString()))

val result: Int = evalWithLogging(Sum(Sum(num1, num2), num3))
txt_cal_result.setText("When 블록 사용 : " + result.toString())
txt_cal_log.setText(log)
}
}

// if 연쇄를 사용해 계산
fun eval1(e: Expr): Int {
if (e is Num) {
val n = e as Num // 위에서 이미 is Num으로 인해 스마트 캐스트 되어 as Num하여 타입을 변경할 필요 없다
// 자바에서는 instanceof로 타입을 검사한 후 명시적으로 타입을 변경해줘야 하지만 코틀린에선 is로 타입을 검사 하면 스마트 캐스팅되어 해당 타입으로 사용이 가능하다
return n.value
}
if (e is Sum) {
return eval1(e.right) + eval1(e.left) // 변수 e에 대해 스마트 캐스트를 사용한다
}
throw IllegalArgumentException("Unknown expression")
}

// 리팩토링 1 - 값을 만들어내는 if 식
fun eval2(e: Expr): Int =
if (e is Num) {
e.value
} else if (e is Sum) {
eval2(e.right) + eval2(e.left)
} else {
throw IllegalArgumentException("Unknown expression")
}

// 리팩토링 2 - if 중첩 대신 when 사용하기
fun eval3(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval3(e.right) + eval3(e.left)
else -> throw IllegalArgumentException("Unknown expression")
}

// 리팩토링 3 - 분기에 복잡한 동작이 들어가 있는 when 사용하기
fun evalWithLogging(e: Expr): Int =
when (e) {
is Num -> {
log += "num: ${e.value}\n"
e.value
}
is Sum -> {
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
log += "sum: $left + $right\n"
left + right
}
else -> throw IllegalArgumentException("Unknown expression")
}
}



3. 실행 결과


포스팅 OS : Mac

검색어 : 코틀린(Kotlin), enum, when, 스피너(Spinner), 임포트(import)



▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기

2018/03/15 - [Android_Kotlin] - [Android Kotlin] 문자열 템플릿(String Template) 사용법

2018/06/05 - [Android_Kotlin] - [Android Kotlin] 클래스, 프로퍼티, 커스텀 접근자 - 라디오 버튼(Radio Button)





이번에는 enum과 when을 사용하는 방법에 대하여 포스팅하겠습니다. 


enum과 when을 충분히 사용해 볼수 있는 예제로 색을 혼합해 혼합된 색상에 대해 출력해주는 액티비티를 만들겠습니다.


참고로 제가 안드로이드 예제를 통한 학습방법을 고집하는 이유는 단순히 코틀린만을 공부하는게 아니라 코틀린을 안드로이드에 적절히 사용하는 방법도 같이 익히기 위해서 입니다. 제가 작성하는 포스팅을 처음부터 차근차근 보다보면 코틀린을 공부함과 동시에 안드로이드 앱을 코틀린으로 제작하는 방법도 저절로 배우게 되실 거라고 봅니다.



1. Color 클래스

enum class Color (
// 상수의 프로퍼티를 정의
val r: Int, val g: Int, val b: Int
) {
// 각 상수를 생성할 때 그에 대한 프로퍼티 값을 지정
RED(255, 0, 0),
ORANGE(255, 165, 0),
YELLOW(255, 255, 0),
GREEN(0, 255, 0),
BLUE(0, 0, 255),
INDIGO(75, 0, 130),
VIOLET(238, 130, 238); // 마지막엔 반드시 세미콜론(;)을 사용해야 한다.

// enum 클래스 안에서 메소드를 정의
fun rgb() = "R : " + r + " G : " + g + " B : " + b
}



2. 레이아웃

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Activity.EnumWhenActivity">

<TextView
android:text="1. 색 정보 보기"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp" />
<TextView
android:id="@+id/txt_color_result"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="20dp"
android:textStyle="bold"
android:gravity="center" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3">
<Button
android:id="@+id/btn_red"
android:text="Red"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>

<Button
android:id="@+id/btn_orange"
android:text="Orange"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>

<Button
android:id="@+id/btn_yellow"
android:text="Yellow"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:id="@+id/btn_green"
android:text="Green"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>

<Button
android:id="@+id/btn_blue"
android:text="Blue"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>

<Button
android:id="@+id/btn_indigo"
android:text="Indogo"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>

<Button
android:id="@+id/btn_violet"
android:text="Violet"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"/>
</LinearLayout>


<TextView
android:text="2. 혼합할 색상을 골라주세요"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="8"
android:gravity="center">
<TextView
android:text="1번 색"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"/>
<Spinner
android:id="@+id/spn_first"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="3"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="8"
android:gravity="center">
<TextView
android:text="2번 색"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"/>
<Spinner
android:id="@+id/spn_second"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="3"/>
</LinearLayout>
<Button
android:id="@+id/btn_mix"
android:text="Mix"
android:layout_width="match_parent"
android:layout_height="50dp"/>

<TextView
android:id="@+id/txt_mix_result"
android:layout_width="match_parent"
android:layout_height="80dp"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center"/>

</LinearLayout>



3. res > values > string.xml String Array 삽입

<string-array name="colorList">
<item>Red</item>
<item>Orange</item>
<item>Yellow</item>
<item>Green</item>
<item>Blue</item>
<item>Indogo</item>
<item>Violet</item>
</string-array>



4. 소스

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import com.kotlin_test.R
import com.kotlin_test.model.Color
import com.kotlin_test.model.Color.*
import kotlinx.android.synthetic.main.activity_enum_when.*

class EnumWhenActivity : AppCompatActivity() {

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

// 색 정보 보기 구간 ---------------------------------------------------------------------------
btn_red.setOnClickListener {
txt_color_result.setText(getMsg(Color.RED))
}

btn_orange.setOnClickListener {
txt_color_result.setText(getMsg(Color.ORANGE))
}

btn_yellow.setOnClickListener {
txt_color_result.setText(getMsg(Color.YELLOW))
}

btn_green.setOnClickListener {
txt_color_result.setText(getMsg(Color.GREEN))
}

btn_blue.setOnClickListener {
txt_color_result.setText(getMsg(BLUE))
}

btn_indigo.setOnClickListener {
txt_color_result.setText(getMsg(Color.INDIGO))
}

btn_violet.setOnClickListener {
txt_color_result.setText(getMsg(Color.VIOLET))
}


// 색 혼합 구간 -------------------------------------------------------------------------------
var firstColor : Color? = RED
var secondColor : Color? = RED

// 스피너 셋팅
val spnFirst = findViewById(R.id.spn_first) as Spinner
val spnSecond = findViewById(R.id.spn_second) as Spinner
val adapter = ArrayAdapter.createFromResource(this, R.array.colorList, android.R.layout.simple_spinner_item)

// 첫 번째 스피너
spnFirst.adapter = adapter
spnFirst.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, position: Int, l: Long) {
firstColor = setColor(position)
}

override fun onNothingSelected(adapterView: AdapterView<*>) {

}
}

// 두 번째 스피너
spnSecond.adapter = adapter
spnSecond.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, position: Int, l: Long) {
secondColor = setColor(position)
}

override fun onNothingSelected(adapterView: AdapterView<*>) {

}
}

// Mix 버튼
btn_mix.setOnClickListener {
txt_mix_result.setText("mix : " + mix(firstColor, secondColor) + "\n" +
"mixOptimized : " + mixOptimized(firstColor, secondColor))
}
}

fun getMsg(color : Color) = "색상 코드 : ${color.rgb()}\n" +
"연관 단어1 : ${getMnemonic(color)}\n" +
"연관 단어2 : ${getWarmth(color)}"

// import com.kotlin_test.model.Color.*
// 짧은 이름으로 사용하기 위해 enum 상수를 모두 임포트 하면 아래와 같이 RED, ORANGE 등으로 사용 가능합니다
fun setColor(positon: Int) =
when (positon) {
0 -> RED
1 -> ORANGE
2 -> YELLOW
3 -> GREEN
4 -> BLUE
5 -> INDIGO
6 -> VIOLET
else -> null
}

// when을 사용해 올바른 enum 값 찾기
fun getMnemonic(color: Color) =
when (color) {
RED -> "Richard"
ORANGE -> "Of"
YELLOW -> "York"
GREEN -> "Gave"
BLUE -> "Battle"
INDIGO -> "In"
VIOLET -> "Vain"
}

// 한 when 분기 안에 여러 값 사용하기
// 콤마로 구분한다.
fun getWarmth(color: Color) =
when(color) {
RED, ORANGE, YELLOW -> "warm"
GREEN -> "neutral"
BLUE, INDIGO, VIOLET -> "cold"
}

// when의 분기 조건에 여러 다른 객체 사용하기
// 비효율 적인 코드 - 여러 set 인스턴스를 생성하기 떄문에
fun mix(c1: Color?, c2: Color?) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> "ORANGE"
setOf(YELLOW, BLUE) -> "GREEN"
setOf(BLUE, VIOLET) -> "INDIGO"
else -> "Dirty color"
}

// 인자가 없는 when
// when에 인자가 없으면 각 분기의 조건이 Boolean 결과를 계산하는 식이어야 한다.
// 위 mix 함수보다 불필요한 객체 생성을 막을 수 있어서 효율적이다. 비록 코드는 약간 읽기 어려워지지만 성능 향상이 가능하다
fun mixOptimized(c1: Color?, c2: Color?) =
when {
(c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> "ORANGE"
(c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> "GREEN"
(c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) -> "INDIGO"
else -> "Dirty color"
}
}



5. 실행 결과



포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 클래스(Class), 프로퍼티(Property), 커스텀 접근자, 라디오 버튼(Radio Button)



▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기

2018/03/15 - [Android_Kotlin] - [Android Kotlin] 문자열 템플릿(String Template) 사용법




2달만에 다시 글을 쓰게 되네요. 제가 투입된 프로젝트가 바빠져서 한동안 블로그엔 신경을 못썼습니다. 이제 좀 상황이 정리되어 다시 열심히 달려보려 합니다! 





오늘 포스팅할 주제는 코틀린의 클래스와 프로퍼티 입니다. 역시 제 포스팅 스타일대로 안드로이드 예제로 설명하려 합니다. 



우선 액티비티 하나를 만들어서 두 개의 예제로 진행하려 합니다. 

예제에 대해 간단히 설명드리면,

첫 번째 예제는 Person 이라는 객체를 생성하여 이름과 결혼 여부를 저장하고 저장된 값을 텍스트 뷰에 출력해줍니다.

두 번째 예제는 Rectangle 이라는 객체를 생성하여 가로 세로의 길이를 입력하여 저장하고 커스텀 접근자를 사용하여 정사각형 여부를 텍스트 뷰에 출력해줍니다.


늘 그렇듯 아래 소스에 주석으로 설명을 달아 놓았으니 소스 보시고 직접 실행해보시면서 이해하시면 간단합니다.

이전 포스팅에서 다뤘던 내용은 주석으로 달지 않고 최대한 소스에 적용해서 작성했습니다. 이해가 안가시는 부분은 이전 포스팅에서 찾아서 보시길 바랍니다.



1. Person 클래스

class Person(
/*
프로퍼티 생성 - 필드(변수), 접근자(Getter, Setter)를 한데 묶어 프로퍼티라 합니다.
자바와는 다르게 코틀린에서 프로퍼티 생성 시 Getter, Setter등의 접근자를 따로 생성해줄 필요가 없습니다.

ex) 코틀린으로 생성된 Person을 자바로 생성했을 경우 소스 예제입니다.
public class Person {
private final String name;
private boolean isMarried;

public Person(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setMarried(boolean married) {
isMarried = married;
}

public boolean isMarried() {
return isMarried;
}
}

위 처럼 긴 소스를 코틀린은 아래와 현재 이 클래스와 같이 간단하게 생성이 가능합니다.
*/

// val - 읽기 전용 프로퍼티
// var - 읽기, 쓰기 전용 프로퍼티
val name: String,
var isMarried : Boolean = false
)




2. Rectangle 클래스

class Rectangle (val height : Int, val width : Int) {
// 커스텀 접근자 생성
val isSquare : Boolean
/* // 블록을 본문으로 사용하는 방법
get() {
return height == width
}
*/
// 식을 본문으로 사용하는 방법
get() = height == width
}



3. 레이아웃

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Activity.PropertyActivity">

<TextView
android:text="1. Person"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#0054FF"
android:gravity="center"/>
<EditText
android:id="@+id/edt_person_nm"
android:hint="이름을 입력하세요"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"
android:gravity="center"
android:background="@null"/>

<RadioGroup
android:id="@+id/rdo_married"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<RadioButton
android:id="@+id/rbtn_married_false"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="미혼"
android:paddingRight="20dp"/>
<RadioButton
android:id="@+id/rbtn_married_true"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="기혼" />
</RadioGroup>

<Button
android:id="@+id/btn_person_save"
android:text="저장"
android:layout_width="match_parent"
android:layout_height="50dp" />

<Button
android:id="@+id/btn_person_print"
android:text="출력"
android:layout_width="match_parent"
android:layout_height="50dp" />

<TextView
android:id="@+id/txt_person_result"
android:layout_width="match_parent"
android:layout_height="80dp"
android:textSize="20sp"
android:gravity="center"/>


<TextView
android:text="2. Rectangle"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#0054FF"
android:gravity="center"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="4">
<EditText
android:id="@+id/edt_width"
android:hint="가로 길이"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:background="@null"
android:inputType="number"
android:gravity="center"/>
<EditText
android:id="@+id/edt_height"
android:hint="세로 길이"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="2"
android:background="@null"
android:inputType="number"
android:gravity="center"/>
</LinearLayout>

<Button
android:id="@+id/btn_rect_save"
android:text="저장"
android:layout_width="match_parent"
android:layout_height="50dp" />

<Button
android:id="@+id/btn_rect_print"
android:text="정사각형 여부 판독"
android:layout_width="match_parent"
android:layout_height="50dp" />

<TextView
android:id="@+id/txt_rect_result"
android:layout_width="match_parent"
android:layout_height="80dp"
android:textSize="20sp"
android:gravity="center"/>

</LinearLayout>



4. 액티비티 소스

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.kotlin_test.R
import com.kotlintest.model.Person
import com.kotlintest.model.Rectangle
import kotlinx.android.synthetic.main.activity_property.*

class PropertyActivity : AppCompatActivity() {

private var person : Person? = null
private var isMarried : Boolean = false

private var rect : Rectangle? = null

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

// ---------------
// 1. Person
// ---------------
// 결혼 유무 선택
rdo_married.setOnCheckedChangeListener { radioGroup, i -> if(i == R.id.rbtn_married_true) isMarried = true else isMarried = false}

// 저장
btn_person_save.setOnClickListener {
person = Person(edt_person_nm.text.toString(), isMarried)
txt_person_result.setText("저장 완료!")
}

// 출력
btn_person_print.setOnClickListener {
val stringMarried : String = if(person != null) person?.isMarried.toString() else "false"
val marriedYn : Boolean

if ( stringMarried.equals("true"))
marriedYn = true
else
marriedYn = false

txt_person_result.setText("이름 : ${person?.name}\n결혼유무 : ${if(marriedYn) "기혼" else "미혼" }")
}

// ---------------
// 2. Rectangle
// ---------------
// 저장
btn_rect_save.setOnClickListener {
rect = Rectangle(Integer.parseInt(edt_height.text.toString()), Integer.parseInt(edt_width.text.toString()))
txt_rect_result.setText("저장 완료!")
}

// 정사각형 여부 판독
btn_rect_print.setOnClickListener {
val stringSquare : String = if(rect != null) rect?.isSquare.toString() else "false"
val isSquare : Boolean
if(stringSquare.equals("true")) isSquare = true else isSquare = false

if(isSquare) txt_rect_result.setText("정사각형") else txt_rect_result.setText("직사각형")
}
}
}



5. 실행 결과





이번 포스팅을 직접 테스트해보시면 코틀린에서 자바대비 얼마나 소스의 양을 줄일 수 있을지 가늠하실 수 있을 것 같네요. 



포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 문자열 템플릿(String Template)


▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 함수와 변수를 이용하여 에디트텍스트(EditText)에 입력한 값 중 큰 값 구하기




이번에는 문자열 템플릿에 대해 포스팅하겠습니다. 간단한 기능이므로 포스팅도 매우 간략하게 쓰겠습니다.



문자열 템플릿은 사실 이전 포스팅에서 사용한 적이 있습니다.

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린

바로 위 포스팅에서 몰래(?) 사용했었죠. 




사용한 소스 코드를 한번 보시죠.

btn_print_02.setOnClickListener {
// 변경 불가능한 변수 - val
// 자바로 말하면 final
val nameStr : String = "Kotlin_02"
txtHellow.setText("Hellow $nameStr")
}

위 소스는 버튼 클릭시 'Hellow Kotlin_02' 이라는 메시지를 출력하는 소스입니다. 




txtHellow.setText("Hellow $nameStr")

바로 여기가 문자열 템플릿을 사용한 부분이죠. 이렇게 '$' 문자를 사용해서 nameStr 변수를 따옴표(" ")안에서 바로 사용할 수 있습니다. 자바에서는 없던 기능이죠. 

자바에서는 "Hellow" + nameStr 이렇게 사용했던 것이 '$' 문자 하나로 간단하게 사용이 가능해졌습니다. 




문자열 템플릿에서 사용할 수 있는 대상은 변수 이름만으로 한정되지 않습니다. 복잡한 식도 중괄호({ })로 둘러싸서 문자열 템플릿 안에 넣을 수 있습니다.

btn_print_02.setOnClickListener {
// 변경 불가능한 변수 - val
// 자바로 말하면 final
val nameStr : String = "Kotlin_02"
txtHellow.setText("Hellow ${if(nameStr.equals("")) "Kotlin" else nameStr}")
}

이런식으로 ${ } 중괄호 안에 식을 넣어 사용이 가능합니다. 




대체로 $를 그냥 사용하는 것 보다는 ${ } 처럼 중괄호를 써서 사용하는 습관을 들이는 것을 추천합니다. 그 이유는 문자와 변수명의 구분이 확실하고 코드를 읽을 때도 문자열 템플릿 안에서 변수가 쓰인 부분을 더 쉽게 식별이 가능하기 때문입니다.


문자와 변수명 구분이 확실하다는 의미는 아래 소스를 보시면 이해가 쉽습니다.

"$nameStr님 안녕하세요."

위와 같이 사용하면 에러가 납니다. 이유는 간단합니다. 코틀린에서는 자바와 마찬가지로 한글(한글 뿐 아니라 '글자(letter)'로 분류할 수 있는 모든 유니코드 문자)을 식별자에 사용할 수 있어서 변수 이름에 한글이 들어갈 수 있습니다. 위 소스에서 실제로 변수명은 'nameStr'이지만 컴파일러는 'nameStr님'으로 인식해서 변수가 없다고 에러가 나는 겁니다.

"${nameStr}님 안녕하세요."

이렇게 사용하면 간단하게 해결 됩니다. 보기에도 변수라는게 인식하기 쉽지 않나요?



문자열 템플릿은 자바에서 없던 기능인 만큼 유용하게 활용이 가능할 것으로 보입니다. 자바에서 " " + " "  남발해서 보기에도 안좋고 보기도 힘든 상황을 많이 겪어보신 분들이라면 쌍수를 들고 환영할만한 기능임에는 분명합니다.

포스팅 OS : Mac

검색어 : 코틀린(Kotlin), 함수(Function), 변수(Variable), 에디트 텍스트(Edit Text)


▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅

2018/03/14 - [Android_Kotlin] - [Android Kotlin] 텍스트뷰(TextView)와 버튼(Button)을 사용한 헬로 코틀린



이번에는 코틀린의 함수와 변수에 대해 간단하게 알아보도록 할텐데 에디트텍스트에 입력한 두 개의 정수 중 큰 값을 출력하는 액티비티를 만들어 보겠습니다.


이번에도 역시 설명은 주석으로 보시면 되겠습니다. 사실 주석으로 설명을 달아 놓는 이유가 지금 포스팅 하는 소스들을 하나의 공부용 앱으로 만들어서 Git에 업로드 할 예정이라 소스만 보고도 이해가 가능해야 해서 이런 방식을 채택하게 되었습니다.



1. 레이아웃


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Activity.FunctionActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="4">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="첫 번째 :"
android:gravity="center"/>
<EditText
android:id="@+id/edt_01"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="두 번째 :"
android:gravity="center"/>
<EditText
android:id="@+id/edt_02"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"/>

</LinearLayout>
<Button
android:id="@+id/btn_result1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Max 1"/>
<Button
android:id="@+id/btn_result2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Max 2"/>
<Button
android:id="@+id/btn_result3"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Max 3"/>

<TextView
android:id="@+id/txt_result"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="20sp"/>

</LinearLayout>





2. 소스


import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.kotlin_test.R
import kotlinx.android.synthetic.main.activity_function.*

class FunctionActivity : AppCompatActivity() {

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

// var : 변경 가능한 변수 선언
var maxNum : String

// MAX 1 버튼
btn_result1.setOnClickListener {

// val : 변경 불가능한 변수 선언
val num01 : Int = Integer.parseInt(edt_01.text.toString())

/*
타입 추론 기능에 의해 num01 변수와는 다르게 타입 지정을 생략할 수 있다. (: Int 생략 가능)
단, 변수 생성과 동시에 값을 초기화 해줄 경우에만 생략이 가능하다.
변수 초기화를 나중에 진행할 경우 아래와 같이 반드시 타입을 지정해 주어야 한다
val num02 : Int
*/
val num02 = Integer.parseInt(edt_02.text.toString())

maxNum = max1(num01, num02).toString()

txt_result.text = maxNum
}

// MAX 2 버튼
btn_result2.setOnClickListener {

val num01 : Int = Integer.parseInt(edt_01.text.toString())
val num02 = Integer.parseInt(edt_02.text.toString())

maxNum = max2(num01, num02).toString()

txt_result.text = maxNum
}

// MAX 3 버튼
btn_result3.setOnClickListener {

val num01 : Int = Integer.parseInt(edt_01.text.toString())
val num02 = Integer.parseInt(edt_02.text.toString())

maxNum = max3(num01, num02).toString()

txt_result.text = maxNum
}
}

// 블록이 본문인 함수
fun max1(a: Int, b : Int) : Int {
return if (a > b) a else b
}

// 식이 본문인 함수
fun max2(a : Int, b : Int) : Int = if (a > b) a else b

/*
식이 본문인 함수 간략화 (: Int 반환 타입 지정 생략)
식이 본문일 경우 굳이 사용자가 반환 타입을 적지 않아도 컴파일러가 함수 본문 식을 분석해서
식의 결과 타입을 함수 반환 타입으로 정해준다
이렇게 컴파일러가 프로그래머 대신 타입을 정해주는 기능을 <타입 추론>이라 부른다.
*/
fun max3(a: Int, b : Int) = if (a > b) a else b
}



3. 실행 결과





포스팅 OS : Mac

검색어 : 안드로이드(Android), 코틀린(Kotlin), 텍스트뷰(TextView), 버튼(Button)




▶︎ 이전 포스팅 목록

2018/02/10 - [Android_Kotlin] - [Android Kotlin] 안드로이드 스튜디오(Andorid Studio)에 코틀린(Kotlin) 개발환경 셋팅



이전 포스팅에서는 안드로이드 스튜디오에 코틀린 개발환경을 셋팅하는 방법에 대해 알아보았습니다. 오늘은 텍스트뷰와 버튼의 기본적인 사용법에 대해 알아보려고 합니다. 개발환경 셋팅 후 처음으로 만들어보는 Hellow Kotlin 예제라고 생각하시면 됩니다.


참고로 앞으로 기본적인 설명은 왠만하면 주석으로 대체할 생각이며 안드로이드 코틀린 포스팅의 경우 자바를 어느정도 이해하시고 있다고 가정하고 진행합니다.


1. 레이아웃


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kotlin_test.Activity.HellowWorldActivity">

<TextView
android:id="@+id/txtHellow"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20dp"
android:textStyle="bold"
android:gravity="center"/>

<Button
android:id="@+id/btn_clear"
android:text="Text Clear"
android:layout_width="match_parent"
android:layout_height="50dp" />

<Button
android:id="@+id/btn_print_01"
android:text="print_01"
android:layout_width="match_parent"
android:layout_height="50dp" />
<Button
android:id="@+id/btn_print_02"
android:text="print_02"
android:layout_width="match_parent"
android:layout_height="50dp" />

<Button
android:id="@+id/btn_print_03"
android:text="print_03"
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>







2. 소스


import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.kotlin_test.R
import kotlinx.android.synthetic.main.activity_hellow_world.*

class HellowWorldActivity : AppCompatActivity() {

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

btn_clear.setOnClickListener {
txtHellow.setText("")
}

btn_print_01.setOnClickListener {
txtHellow.setText("Hellow Kotlin_01")
}

// val 변수 사용
btn_print_02.setOnClickListener {
// 변경 불가능한 변수 - val
// 자바로 말하면 final
val nameStr : String = "Kotlin_02"
txtHellow.setText("Hellow $nameStr")
}

// var 변수 사용
btn_print_03.setOnClickListener {
// 변경 가능한 변수 - var
var nameStr : String = "Test"
nameStr = "Kotlin_03"
txtHellow.setText("Hellow $nameStr")
}

}
}


위 소스를 보시면 자바와는 다른점이 확연히 느껴지실 겁니다. 달라진 점에 대해서는 차근차근 차후 포스팅에서 설명하겠지만 현재 눈에 보이는 가장 큰 차이는 코틀린은 데이터바인딩을 지원해서 레이아웃에 있는 뷰를  findViewById 할 필요가 없이 바로 id로 호출하여 사용이 가능하다는 점입니다.




3. 실행 결과






포스팅 OS : Windows 10

검색어 : 코틀린(Kotlin), 셋팅(Setting), 셋업(Setup), 설치(Install)


앞으로 매번 포스팅 글 상단에 포스팅 OS를 기재해 놓을 생각입니다. 그 이유는 제가 노트북은 맥이고 데스크탑은 Windows를 사용하고 있어서 수시로 바뀔 예정이라 항상 상단에 표기해 놓도록 하겠습니다. 운영체제가 바뀐다 하여도 단축키나 메뉴의 위치 말고는 큰 영향이 없기에 무리 없을 것으로 판단됩니다. (이정도 차이조차 극복하지 못하신다면 개발 자체가 힘든분이라 생각됩니다...)



1. 코틀린(Kotlin) 플러그인 설치


1) 안드로이드 스튜디오 3.0 이전 버전


현재 설치되어 있는 안드로이드 스튜디오가 2.x 버전일 경우에는 플러그인을 설치해야 합니다.


File -> settings -> Plugins 에서 검색창에 Kotlin으로 검색하시면 JetBrains사에서 만든 플러그인이 딱 1개 나옵니다. install 버튼을 눌러서 설치하시면 됩니다. (아래 사진에는 이미 설치되어 있는 관계로 Uninstall 버튼이 표시되고 있습니다.)




2) 안드로이드 스튜디오 3.0 이상 버전


안드로이드 스튜디오 3.0 이상 버전일 경우에는 별도의 플러그인 설치 없이 바로 코틀린 사용이 가능합니다. 아래 사진처럼 include Kotlin support에 체크 후 프로젝트를 생성하면 코틀린으로 만들어진 메인 액티비티가 생성됩니다.





2. 프로젝트 그래들 셋팅


안드로이드 스튜디오 3.0 이상 버전일 경우 바로 위 사진처럼 include Kotlin support에 체크 후 사용해 프로젝트를 생성하면 아래와 같이 코틀린으로 생성된 메인 액티비티가 반겨줍니다.

class MainActivity : AppCompatActivity() {

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


이제 그래들을 살펴 보겠습니다. 우선 build.gradle(Project : ...) 를 살펴보면 아래와 자바 프로젝트와 다른 점이 보입니다.

buildscript {
ext.kotlin_version = '1.2.21'
    ...
}

코틀린 버전을 입력해놓은 변수가 보입니다. 이걸 보면 딱 감이 옵니다. 코틀린이라는 언어를 라이브러리 처럼 사용하고 있구나... 라고 말이죠.

그럼 이제 build.gradle(Module:app)으로 가보겠습니다. 

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

역시 생각대로 코틀린 라이브러리가 컴파일 되어 있는 것이 보입니다. 이걸 보면 기존에 자바 프로젝트에도 코틀린을 사용할 수 있다는 것을 알 수 있습니다.

여기서 눈썰미 있는 분들은 compile -> implementation 로 명령어가 바뀌어 있는 것을 눈치채셨을 겁니다. 이부분에 대한 설명은 지금은 중요한 것이 아니니 다음에 기회되면 포스팅하도록 하겠습니다. 지금은 그냥 compile 명령어가 바뀌었다라고만 알고 계시면 됩니다. 

(물론 implementation 대신 compile 명령어를 사용하셔도 작동합니다.)

 



3. Anko 라이브러리 추가


여기까지 코틀린 플러그인을 설치하고 코틀린을 사용한 프로젝트의 그래들까지 살펴보았습니다. 하지만 여기서 개발환경 셋팅의 끝이 아닙니다. 코틀린을 이용하여 안드로이드 앱을 개발할 때 조금 더 편리하게 사용가능하도록 도와주는 라이브러리가 있습니다. 그중 Anko는 가장 강력한 라이브러리 중 하나입니다. 가장 최신 Anko버전을 확인하려면 Anko repository에서 확인가능합니다.


아래와 같이 gradle에 추가해주시면 됩니다.

/* bulid.gradle(Project:...) */
buildscript {
ext.kotlin_version = '1.2.21'
ext.anko_version = '0.10.3'
    ...
}


/* bulid.gradle(Module:app) */
dependencies {
...
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "org.jetbrains.anko:anko:$anko_version"
...
}

Anko 라이브러리가 가지고 있는 기능은 해당 기능을 사용할때 하나하나 포스팅하도록 하겠습니다. 지금은 안드로이드 앱을 코틀린으로 개발시 필수 라이브러리라고 생각하시면 됩니다. 여기까지 하셨으면 기본적인 안드로이드 스튜디오에 코틀린 개발환경 셋팅은 끝난 것입니다. 




4. Hellow Kotlin 실행


Hellow Kotlin을 실행해보도록 하겠습니다. 


- activity_main

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.network_kotlin_test.MainActivity">

<TextView
android:id="@+id/txt_hellow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:gravity="center" />

</LinearLayout>

- MainActivity.kt

class MainActivity : AppCompatActivity() {

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

txt_hellow.text = "Hellow Kotlin"
}
}


위와 같이 셋팅하고 실행하면 아래와 같이 화면에 Hellow Kotlin이 출력되는 것을 확인할 수 있습니다.




이제 코틀린으로 안드로이드 앱을 개발하기 위한 셋팅을 마쳤습니다. 처음 써보는 포스팅인지라 많이 부족합니다. 최대한 알아보기 쉽게 작성하려고 노력하였으나 제 의도대로 쓰였는지 모르겠습니다. 그럼 이만 마치겠습니다.




+ Recent posts