728x90
반응형

클래스 선언은 java와 동일하고 객체 선언할 때 new 키워드는 사용하지 않는다.

클래스 생성자

1. Primary 생성자 : 매개변수들이 멤버 변수로 자동 추가됨

- class 옆에 constructor 키워드를 사용해서 생성(constructor 빼도 됨)

class Person constructor(val name:String){

}
class Person2(val name:String){}
fun main(){
    val person = Person("김태헌")
    println(person.name)
    val person2 = Person2("너굴맨")
    println(person2.name)
}

- 초기화 블록을 활용하여 초기화 할 수 있다

- 복잡한 초기화할 때 초기화 블럭을 사용한다.

class Person3(val name:String){
    init{
        println(name)
    }
}

 

2. Secondary 생성자

- 매개변수들이 멤버 변수로 추가되지 않음

- 생성자 오버로딩의 개념으로 여러 개의 생성자 정의시 사용함

- 반드시 Primary 생성자를 호출해야 함!

class Person4{
    var name:String?=null
    constructor(name:String){
        this.name=name
    }
    fun printName():Unit{
        println(name)
    }
}
fun main(){
    val person = Person4("김태헌")
    person.printName()
}

- Primary 생성자에게 매개변수를 정의 : 생성자에서 수행할 내용 없으면 { } 생략 가능

package FirstWeek.practice

class Person(val name:String,val addr:String, val tel:String){
    constructor(name:String,addr:String):this(name,addr,"")
    constructor(name:String):this(name,"","")
    constructor():this("","","")
}
fun main(){
    val person1 =Person("김태헌","Seoul","010-7757-6342")
    val person2 = Person("김태헌","Seoul")
    val person3 = Person("김태헌")
    val person4 = Person()
}

- 보통 클래스 선언할 때 멤버변수로 포함되어야 하는 멤버들은 primary생성자에 포함시킨다

- Secondary 생성자로 다양하게 만들어서 객체 다양화 한다.

 

접근제한자

1. Public : 전체 공개 default

2. Private : 현재 파일 내에서만 사용 가능(현재 클래스 or 인터페이스에서만 사용 가능)
3. Protected : subclass에서 사용 가능

4. Internal : 같은 모듈 내에서만 사용 가능

 

클래스의 상속

- 코틀린의 모든 기본 클래스는 상속이 불간으함

- 클래스 상속을 하려면 open 키워드를 추가해야 함 : 단일 상속만 가능

 

 

추상 클래스

- 인스턴스화 할 수 없는 클래스 : abstract 키워드가 선언되어 있거나 abstract method를 포함하고 있는 클래스

-> 추상 메소드는 상속을 통해 오버라이딩해 주어야 한다

-> Open 키워드 생략한다(자동으로 상속가능한 class)

package FirstWeek.practice

abstract class A{
    abstract fun func()
    open fun fun2(){
        
    }
}
class B:A(){
    override fun func() {
        TODO("Not yet implemented")
    }

    override fun fun2() {
        super.fun2()
        println("Hello")
    }
}
fun main(){
    
}

 

인터페이스

자바의 인터페이스와 동일한 기능을 수행한다. 인터페이스란 오버라이딩 하기위한 멤버들을 모아놓은 것이다. 변수도 선언만 가능하며, 다중 상속이 가능하다.

package FirstWeek.practice

interface Runnaable{
    var type:Int
    fun run()
    fun fastRun() = println("빨리 달린다")
}

class RunnableClass:Runnaable{
    override var type:Int = 0
    override fun run() {
        println("달리다")
    }
}

- 인터페이스와 클래스 다중 상속 가능하며, 순서 상관 없음

 

중첩 클래스 : 정적 멤버 클래스, 인스턴스 멤버 클래스

- 클래스 내에 선언된 정적인 클래스

package FirstWeek.practice

class sOuterClass{
    var num1 = 10
    class NestClass{
        var num2 = 20
        fun something1(){
            println(num2)
        }
        fun something2()=20
    }
}
fun main(){
    val a = sOuterClass.NestClass()
    a.something1()
    val b = sOuterClass.NestClass().something2()
}

 

내부(Inner) 클래스

- Java의 인스턴스 멤버 클래스 개념과 동일

 - Outerclass의 객체를 생성해야만 사용할 수 있는 중첩 클래스

 - Outerclass의 멤버 엑세스 가능

   - Outerclass 객체 생성 필요

package FirstWeek.practice

class outerclass{
    var num = 10
    inner class InnerClass{
        fun something1(){
            num = 20
            println(num)
        }
        fun something2()=20
        fun getOuterReferences():outerclass = this@outerclass
    }
}

fun main(){
    val a = outerclass().InnerClass()
    a.something1()
    val b = outerclass().InnerClass().something2()
    val c = a.getOuterReferences()
    println(c.num)
}

 

Companion Object

- java에서의 static 변수 및 메소드 기능이 필요한 경우 사용

package FirstWeek.practice

class Person10{
    fun callMe() = println("I'm called")
}
class Person11{
    companion object{
        fun callMe() = println("I'm called")
    }
}

fun main(){
    val p1 = Person10()
    p1.callMe()
    Person11.callMe()
}

 

Object 클래스

Singleton 패턴의 객체 정의 : 하나의 instance를 가지는 클래스 선언

-> 익명 객체가 필요로 할 때 유용하게 사용됨, 클래스 이름을 객체처럼 사용

package FirstWeek.practice

object Test{
    private var a:Int =0
    var b:Int = 1
    fun makeMe12():Int{
        a = 12
        return a
    }
}

fun main(){
    val result = Test.makeMe12()
    println("b = ${Test.b}")
    println("result = $result")
}

- 인터페이스를 구현한 객체 생성시 사용한다. button마다 전용함수를 장착할 때, Widget, View에 이벤트 달아주고 싶을때 사용한다.

fun main(){
    val obj = object:MouseAdapter(){
        override fun mouseClicked(e: MouseEvent?) {
            super.mouseClicked(e)
        }

        override fun mouseEntered(e: MouseEvent?) {
            super.mouseEntered(e)
        }
    }
}
package FirstWeek.practice

open class Person123(name:String,age:Int){
    init{
        println("name:$name, age:$age")
    }
    fun eat() = println("Eating food")
    fun talk() = println("Talking with people")
    open fun pray() = println("Praying god")
}
val atheist = object:Person123("김태헌",25){
    override fun pray() = println("no pray")
}

fun main(){
    atheist.eat()
    atheist.talk()
    atheist.pray()
}

 

Data 클래스

- 데이터를 저장하는 구조의 클래스 : equals, hashCode, copy, toString, set, get, componenN 자동생성

package FirstWeek.practice

data class User(val name:String, val age:Int)

fun main(){
    val jack = User("jack",29)
    println("${jack.name}")
    
    val u1 = User("John",20)
    val u2 = u1.copy(name="Heon")
    
    val u3 = User("John",123)
    val (name,age) = u3 // 객체 분리 선언
    
    
}

 

Sealed 클래스

- Subclass의 생성 가능성을 제한

  - When 표현식에서 모든 sealed 클래스의 서브클래스를 처리

    - Else문 필요없음

  - 자동 open 클래스

package FirstWeek.practice

open class Expr
class Const(val value:Double):Expr()
class Sum(val left:Expr, val right:Expr):Expr()

fun eval(e:Expr):Double = when(e){
    is Const -> e.value
    is Sum -> eval(e.right)+eval(e.left)
    else->throw IllegalArgumentException("Unknown")
}

 

 

컬렉션(Collections)

List(리스트)
- 같은 자료형의 데이터들을 순서대로 가짐

- 중복 아이템을 가질 수 있고, 추가, 삭제, 수정이 용이함

리스트 생성

- 읽기 전용 리스트 생성 listOf() 메서드 사용

- 변경 가능한 리스트 생성 mutableListOf() 메서드 사용

add : 추가, removeAt : 삭제 , set : tnwjd

val foods = mutableListOf<String>() --> 빈 리스트 생성하기

 

Map(맵)

- 키와 값의 쌍으로 이루어진 자료구조 : 키는 중복될 수 없는 자료구조

- 생성

1. 읽기 전용 맵

val map = mapOf("a" to 1, "b" to 2, "c" to 3)

val value:int = map.getValue("a")

2. 변경 가능한 맵

val citiesMap = mutableMapOf("한국" to "서울)

for((k,v) in citiesMap){

  println("$k -> $v")

}

 

Set(집합)

: 중복되지 않는 요소들로 구성된 자료구조

1. 읽기 전용집합

val citySet = setOf("서울","수원", "부산")

2. 변경 가능한 집합

val citySet2 = mutableSetOf("서울","수원")

728x90
반응형

'App > Android' 카테고리의 다른 글

[3] Kotlin : 제어문, 함수  (0) 2022.03.11
[2] Kotlin  (0) 2022.03.08
[1] Android 소개  (0) 2022.03.08
RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
728x90
반응형

제어문

if문

- java와 같은 형태로 사용 가능함 

- 코틀린에서는 if문을 하나의 표현식으로 간주하며, 값을 반환한다. 변수의 대입문에 식처럼 사용이 가능하다.

(아래와 같이 a>b이면 a가 result에 대입, else에 해당하면 b가 result에 대입된다)

val result = if(a>b) a else b

- 조건에 따라 여러 표현식을 실행해야 하는 경우,
블록의 마지막 값이 반환된다.(if문 내의 블럭 내에 여러 줄의 식이 있다면 리턴값은 마지막줄이 된다.)

--> Kotlin에서는 삼항 연산자를 지원하지 않으므로 이를 if문으로 구현할 수 있는 것이다. 

val a = -9
val b = -11
val max = if(a>b){
    println("$a is larger than $b ")
    println("max variable holds value of a")
    a
}else{
    println("$b is larger than $a")
    b
}

when 문

- Switch 구문에 대응하는 구문, 실행해야할 구문은 화살표 뒤에 해당. when구문은 표현식으로 사용될 수 있다.

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

- when문을 조건문으로 사용한 경우

val start = 0
val end = 100
val score = 60

when(score){
    in 90..end->println("우수함")
    50->println("평균임")
    in start..end -> println("범위에 있음")
    else -> println("범위를 벗어남")
}

 

for문

- For each 구문과 비슷

1. 배열에 있는 값을 가져다가 반복할 수 있다

val numbers = arrayOf(1,2,3,4,5)
for(num in numbers){
    println(num)
}

2. index를 기반으로도 반복할 수 있다

val numbers = arrayOf(1,2,3,4,5)
for(index in numbers.indicies){
    println("number at $index is ${numbers[index]}")
}

여기서 indicies는 arrayOf안에 있는 원소들의 index를 의미한다

 

3. for 내부도 표현하는 방법 여러가지

for(i in 1..3){}
for(i in 0..10 step 2){} // 2씩 건너띄면서 i 증가
for(i in 10 downTo 0 step 2{}
for(i in 1 until 10){}
repeate(10){} // 10번 반복해
val numbers = arrayOf(2,4,6,8,10)
    for(index in numbers.indices step 2){
        println(numbers[index])
    }
//2 6 10 출력됨

while 문 : java와 동일 -> do while도 쓸 수 있다.

    var x = 10
    while(x>0){
        println(x)
        x--
    }
fun main(){
    val items = listOf("사과","오렌지","김태헌")
    var index = 0
    do{
        println("${index}에 있는 item은 ${items[index]}이다.")
        index++
    }while(index<items.size)
}

Break구문

: 가장 가까이의 반복문을 벗어난다

- Labeled break -> 반복문을 한꺼번에 벗어나고 싶을때 사용

   -> 반복문에 label을 붙여주면 된다. label은 label명@을 붙여서 표시해준다.

    first@ for(i in 1..4){
        second@ for(j in 1..2){
            println("i= $i j= $j")
            if(i==2)
                break@second
        }
    }
    	// i= 1 j= 1
	// i= 1 j= 2
	// i= 2 j= 1
	// i= 3 j= 1
	// i= 3 j= 2
	// i= 4 j= 1
	// i= 4 j= 2

각 반복문마다 label 붙여주는 것도 가능하다.

-->(주의) break@first -> 공백이 있으면 안된다.

 

Continue 구문

: 이 구문을 만나면 아래의 구문 실행 생략하고 제어를 반복문으로 옮기는 경우

- Labeled continue : Labeled break문과 비슷하다 (반복문 사용할때 유용하게 사용된다)

here@ for (i in 1..5){
    for(j in 1..4){
        if(i==3||j==2)
            continue@here
        println("i=$i; j=$j")
    }
}

 

Functions 함수

fun 함수(인수1:자료형1, 인수2:자료형2, ...) : 반환자료형 {} 

인자 생략 가능,반환값이 없는 경우 Unit 및 생략가능

fun main(){
    fun greet(str:String):Unit{
        println(str)
    }
    greet("201811177 김태헌")
}

-> 코틀린에서의 인자는 immutable variable( val에 해당-> 변경 불가 )

반환값이 없는 경우 Unit사용해도 된다.

 

- 간단한 값을 반환하는 경우 { } 생략 가능

fun main(){
    fun greet(str:String):Unit{
        println(str)
    }
    // greet("201811177 김태헌")
    fun getName(firstName:String, lastName:String):String = "$firstName $lastName"
    println(getName("김","태헌"))
}

 

디폴트 매개변수

- 매개변수의 값을 입력하지 않으면 디폴트 값을 가지게 된다.

--> 함수 오버로딩과 비슷한 효과를 낼 수 있다

첫번째 인자는 default, 두번째 인자는 새로운 값을 주고싶을때?

--> 매개변수의 이름을 사용하면 매개변수의 위치에 상관없이 사용 가능함

fun main(args:Array<String>){
    foo('x',2) //x 2
    foo() // a 15
    foo('y')// y 15
    foo(number=234) // a 234
}
fun foo(letter:Char='a',number:Int = 15){
    println("$letter $number")
}

 

함수의 다양한 종류

infix 함수 : 함수의 중위적 표현 가능

ex> shift 연산자는 일반 함수였는데 연산자처럼 호출이 가능했음

infix함수이면 p.createPyramid(4)라고 해도 되지만 p createPyramid 4 이렇게 호출도 가능

class Structure(){
    infix fun createPyramid(rows:Int){
        var k=0
        for(i in 1..rows){
            k=0
            for(space in 1..rows-i){
                print(" ")
            }
            while(k!=2*i-1){
                print("* ")
                ++k
            }
            println()
        }
    }
}
fun main(){
    val p = Structure()
    p createPyramid 4 //p.createPyramid(4)와 동일
}

재귀함수(Recursive Function) : 무한 루프에 빠지지 않도록 주의해서 사용

fun factorial(n:Int):Long {
	return if(n==1) n.toLong() else n*factorial(n-1)
}

-> 함수가 계속 stack에 쌓여서 stack overflow를 자주 발생시킨다 -> 코틀린에서는 이를 해결하기 위해 꼬리 재귀 함수(Tail Recursive Function)이라는 것이 있다.

 

꼬리 재귀 함수(Tail Recursive Function)

: 기존의 재귀함수는 모든 재귀 호출이 완료될 때까지는 결과를 얻을 수 없었으나, 꼬리 재귀에서는 계산이 먼저 수행되고, 재귀 호출이 수행되는 구조

- 컴파일러가 stackoverflow가 발생하지 않도록 효율적인 순환 기반의 버전으로 최적화한 것이다.

꼬리 재귀는 '재귀 호출이 끝나면 아무 일도 하지 않고 결과만 바로 반환되도록 하는' 방법이다. 이 방식을 사용하면 이전 함수의 상태를 유지하지도 않고 추가 연산을 하지도 않아서 스택이 넘쳐나는 문제를 해결할 수 있게 된다.

val eps = 1E-15 // 10^-15
tailrec fun findFixPoint(x:Double = 1.0) : Double
 = if(Math.abs(x-Math.cos(x))<eps)x else findFixPoint(Math.cos(x))
 // 꼬리 재귀함수는 아래처럼 순환구조가 되는 형식으로 만들어진다.
private fun findFixPoint():Double{
	var x=1.0
    while(true){
    	val y = Math.cos(x)
        if(Math.abs(x-y)<eps) return x
        x = Math.cos(x)
    }
}

https://joooing.tistory.com/entry/%EC%9E%AC%EA%B7%80-%E2%86%92-%EA%BC%AC%EB%A6%AC-%EC%9E%AC%EA%B7%80-Tail-Recursion

 

꼬리 재귀 (Tail Recursion)

재귀 자체도 머리 속에 과정을 떠올리려고 하면 굉장히 추상적이라 어렵게 느껴지는데 꼬리 재귀 개념까지 한번에 이해하려고하니 글을 읽는 것만으로는 잘 이해가 되지 않았다. 개발자 도구를

joooing.tistory.com

일반 재귀는 값을 받으면, 그 값에 연산을 하고 다른 함수에게 전달을 해줬었다. 하지만 꼬리재귀는 '아무것도 하지 않고' 값을 전달한다.

 

예제. 꼬리재귀 함수

--> 꼬리 재귀 함수를 사용해서 피보나치 수열의 n번째 항을 반환하는 fibonacci 함수를 만들어주세요.

import java.math.BigInteger
fun main(){
    val n=10000
    val first = BigInteger("0")
    val second = BigInteger("1")
    println(fibonacci(n,first,second))
}

fun fibonacci(n:Int,a:BigInteger,b:BigInteger):BigInteger{
    return if(n==0) a else fibonacci(n-1,b,a+b)
}

stackoverflow를 해결하려면 순환구조로 바꾸어 줘야 한다.

import java.math.BigInteger
fun main(){
    val n=10000
    val first = BigInteger("0")
    val second = BigInteger("1")
    println(fibonacci(n,first,second))
}

tailrec fun fibonacci(n:Int,a:BigInteger,b:BigInteger):BigInteger{
    return if(n==0) a else fibonacci(n-1,b,a+b)
}

 

람다 함수(Lambda)

- Kotlin에서는 함수 반환 자료형 생략도 가능했고 블록도 생략해서 함수를 하나의 변수처럼 표현할 수 있었다.

fun add(x:Int,y:Int):Int{
    return x+y
}
fun add2(x:Int,y:Int) = x+y

한번 사용하고 마는 함수들 이름도 필요한가..?

- 람다 함수 : 익명 함수를 간결하게 표현할 수 있는 방법

val add:(Int,Int) ->Int = {x:Int,y:Int->x+y}
val add = {x:Int,y:Int->x+y}

함수가 일반 타입처럼 사용된다. 

- 코틀린의 람다식

- 형식 : { 매개변수 -> 함수내용 }

- 람다 함수는 항상 { } 로 감싸서 표현

- 인수 목록을 나열하고 -> 이후에 본문 위치

- 인자는 ( ) 로 감싸지 않음

- 인자는 형식 추론이 가능하므로 타입 생략 가능

- 함수 반환값은 함수 내용의 마지막 표현식(함수 반환값이 있다면)

- 변수에 람다식을 저장하고, 변수를 일반 함수처럼 사용

  - 변수에 대입하지 않으면 이후 람다 함수를 사용할 수 없음 -> 정의된 이후에 사용할 수 없다.

   -----> 이런 경우

     - 람다 함수 뒤에 ()를 추가하여 함수 호출

     - Run() 함수에 대입해도 바로 함수가 호출되어 실행

{println("Hello")}()
run{println("World")}
fun main(){
    val add = {x:Int,y:Int->x+y} //타입 추론
    val add2:(Int,Int)->Int = {x,y -> x+y} //타입 명시적으로 줌
    println(add(10,20))
    println(add2(10,20))
    val add3 = {x:Int,y:Int -> println(x+y)} //반환안하고 출력
    add3(10,20)
    
    println({x:Int,y:Int->x+y}(10,20))
}

 

SAM(Single Abstract Method) 변환

- 추상 메서드 하나를 인수로 사용할 때만 대신 함수 인수 전달

코틀린에서는 추상 메소드 하나를 인수로 사용할 때는 함수를 인수로 전달하면 편하다. 자바로 작성된 메소드가 하나인 인터페이스를 구현할 때는 대신 함수를 작성할 수 있다.

 

안드로이드에서는 버튼의 클릭 이벤트를 구현할 때 onClick() 추상 메소드만을 가지는 View.OnClickListener 인터페이스를 구현한다.

버튼을 클릭했을 때 실행되는 함수들은 onClickListener라는 interface에 정의되어 있다. 

자바에서는 changeBtn 객체에 setOnClickListener라는 함수를 통해서 interface객체를 입력으로 넣어주게 되는데 onClickListener라는 것은 인터페이스이니까 인터페이스를 구현하는 방법은 여러가지가 있다. 여기서는 익명클래스에 객체를 만들어서 사용하는 경우이다. 익명 클래스로 만들어도 클래스의 이름은 없지만 인터페이스이니까 인터페이스에 정의된 abstract method를 구현해 준다. 

Java

changeBtn.setOnClickListener(new View.OnClickListener() {
	@Override
    public void onClick(View v){
    	changeBtn.setBackgroundColor(Color.CYAN);
    }
});

Kotlin

changeBtn.setOnClickListener{
	view->changeBtn.setBackgroundColor(Color.CYAN)
}
// 구현되는 인터페이스 내에 추상메서드가 딱 하나만 가지고 있을때 객체 대신 람다함수를 인자로 전달

-> 인터페이스에 추상메서드가 하나일때만 쎈 변환 적용.

view라는 인자도 함수내에서 사용안하면 _ 사용하거나 생략할 수 있다.

changeBtn.setOnClickListener{
	_->changeBtn.setBackgroundColor(Color.CYAN)
}

changeBtn.setOnClickListener{
	changeBtn.setBackgroundColor(Color.CYAN)
}

인수를 사용해야될 필요가 있으면 it이라는 키워드를 사용하면 된다. it은 생략된 객체를 접근할 때 사용할 수 있다.

changeBtn.setOnClickListener{
	it.visibility = View.INVISIBLE
}

람다식의 인수가 하나인 경우는 it(view) 로 인수 접근 ---> 여러개인 경우 안됨

 

- 인터페이스에서 추상메서드는 하나인데 추상메서드의 인자가 여러개 있는경우?

--> 인자를 나열해주면 된다

Kotlin

changeBtn.setOnTouchListener{
	v,event-> // 인자 나열
    changeBtn.setBackgroundColor(Color.CYAN) //함수 본문
    false //반환
}

 

- 함수를 인자로 전달했었다

함수도 타입, 값으로도 대입이 된다.

- 함수 타입의 변수 선언 : 함수 타입 변수에서는 리턴을 쓰지 않고, 마지막 줄이 반환됨

val functionType1 : () -> Unit
val functionType2 : (Int) -> Unit
val functionType3 : (Int, String) -> String
functionType1 = { println("greenjoa")}
functionType2 = {age-> println("나이")}
functionType3 = {age,name->println("나이") "나이"}

 

High - Order Function

- 함수의 인수로 함수나 람다식을 받거나 반환할 수 있는 함수

 

확장 함수

- 클래스에 새로운 함수를 추가

  - 기존 방식은 상속을 통해 새로운 클래스를 만들고, 함수 추가

  - 확장함수는 클래스 밖에서 정의된 클래스의 멤버 함수

     - 멤버 함수를 오버로딩한 경우 확장 함수가 호출됨

  - ex> string의 처음과 마지막 문자 삭제 함수 -> string클래스에 존재하지 않는 함수

fun String.removeFirstLastChar():String = this.substring(1,this.length-1) // String내의 substring함수

 

 

예제>

fun calculate(x:Int, y:Int,func:(Int,Int)->Int):Int{
    return func(x,y)
}

fun String.removeFirstLastChar():String = this.substring(1,this.length-1)

fun main(){
    println(calculate(10,20){x,y->x+y})
    println(calculate(10,20){x,y->x*y})
    println(calculate(10,20){x,y->if(x>y)x else y})

    println("HelloWorld".removeFirstLastChar())
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
반응형

'App > Android' 카테고리의 다른 글

[4] Kotlin - 클래스, 컬렉션  (0) 2022.03.13
[2] Kotlin  (0) 2022.03.08
[1] Android 소개  (0) 2022.03.08
RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
728x90
반응형

코틀린은 안드로이드 애플리케이션 공식 개발언어이다. 안드로이드 애플리케이션은 자바와 코틀린으로 개발할 수 있다.

 

코틀린의 특징
- 코틀린 컴파일러는 JVM(자바 가상머신)에서 실행되는 자바 바이트 코드(클래스 파일)를 생성하므로,

자바와 완벽하게 호환되는 크로스 플랫폼을 지원
  - 자바 애플리케이션이 실행 가능한 환경이면 코틀린 애플리케이션도 실행 가능
  - 다음과 같은 애플리케이션 작성 가능
    - 네이티브 애플리케이션
    - 웹 브라우저에서 실행되는 자바스크립트
    - 서버에서 실행되는 Http 서블릿
    - 구글 안드로이드 애플리케이션
- 객체지향 프로그래밍 지원
- 함수형 프로그래밍 지원함
- 문법과 코드 간결

- 코틀린 개발 IDE : IntelliJ, Android Studio, Eclipse, Compiler

 

기본타입

- 코틀린에서 모든 것이 객체 : 멤버함수나 프로퍼티 호출할 수 있다
- Numbers(Byte,Short,Int,Long,Float,Double), Character(Char), Boolean, Array, String

- Char가 코틀린에서는 숫자형이 아니다

  • Numbers
    • 10진수 : 123
    • 16진수 : 0x0F
    • 2진수 : 0b00000010101001
    • 8진수는 지원하지 않는다
  • Long : 123L
  • Double : 123.9, 123.3e10
  • Float : 13.4f
  • Underscores( _ ) : 숫자가 길어서 실수할 수 있어서 구분자를 주는 것
    • val oneMillion = 1_000_000
    • val creditCardNumber = 1234_5678_3456L

- Explicit Conversions

  - 작은 타입은 큰 타입의 하위 타입이 아니다 -> 작은 타입에서 큰 타입으로 대입이 안된다(서로간에 상속관계가 없다)

모든 숫자 데이터 클래스는 Number라는 추상 클래스를 상속하고 있다
val a:Int =1
val b:Long = a //오류

val a:Int =1
val b:Long = a.toLong()

 

<타입 변환 함수들>
toByte() toShort() toInt() toLong() toFloat() toDouble() toChar()

 

- 산술 연산에서는 묵시적 변환이 이루어짐
val num = 1L + 3 // Long + Int => Long

 

  • Characters
    • char는 숫자로 취급되지 않음, 비교도 하면 안됨 ex> char c ==1 (오류)

변수 및 상수

- 클래스의 멤버 변수 및 전역 변수는 반드시 선언하면서 초기화해야 함

- 지역 변수의 경우, 선언 후 사용 가능하다(단, 초기화가 되어 있지 않으면 사용할 때 에러 발생함)

변수(Variable, mutable variable)

형식 : var variable:Type = value 

var a: Int = 7

var b: Double = 10.5

 

상수(Value, immutable variable) => Java에서는 final 키워드에 해당한다

형식 : val variable:Type = value

val variable:Type = value
val a: Int = 7
val b: Double = 10.5

 

숫자 타입
val a = 100 // 자동 추론(Int) -> 생략 가능
val b:Long = a // 숫자 타입간 변환 자동으로 해주지 않음, Int타입에서 Long타입으로 변환 안된다. 꼭 명시적으로 형변환 해줘야함
val b:Long = a.toLong() // 변환 함수 사용
val b:Long = a + 1L // 표현식을 Long 타입으로 변환 
val b:Long = a+3.5 // 에러난다

 

문자열 : String 타입

// Escape string
val s1 = "hello\nworld"
// Raw String -> 입력형태 그대로 출력한다 (""" """ 사용)
val s2 = """hello world"""
Raw String에는 trim이라는 기능을 사용할 수 있다.
trimIndent() -> 들여쓰기 했던것을 지우겠다.
trimMargin(">") -> 파라미터로 준 기호(여기서는 >)까지 trim하겠다.

 

String 타입을 숫자로 변환하고 싶으면 명시적으로 변환함수를 호출해주면 된다.
toInt() , toDouble()
변수나 상수 출력할때는 $기호를 사용하고 변수명을 주면 된다.

${표현식}--> 계산이 된다.

문자열 비교
== : java의 equals()와 동일

모든 변수는 null을 허용하지 않음
- 객체의 생성과 동시에 초기화해야 함
Null을 허용하려면 물음표(?)를 추가해야 함
- 타입을 생략할 수 없음

var str:String? = "hihello"
str = null (가능)
val a:String //오류
val b:String? = null
var c:String // 오류
var d:String? = null


Variable Nullable
Lateinit 키워드로 나중에 초기화 가능 -> 쓰기전에 초기화 꼭 해주기
- Var 변수에만 사용 가능
- Null 값으로 초기화할 수 없음
초기화 전에는 사용할 수 없음
- Int, Long, Double, Float 등 기본 데이터 타입에는 사용할 수 없음

lateinit var c: String
c="Hello"
println(c)


Lazy로 늦은 초기화
- Val 에 사용하여 늦은 초기화
- 초기화 블록에 초기화에 필요한 코드 작성
- 처음 호출될 때 초기화 블록의 코드가 실행됨
- 마지막 줄에는 초기화할 값을 명시함

val str:String by lazy{
	print("초기화")
	"Hello"
}


이렇게 되면 처음에는
println(str) 하면 초기화Hello
그다음에 println(str) 하면 Hello출력됨

같은 String 타입이여도 Null값을 가질 수 있는 타입과 가질 수 없는 타입으로 구분이 된다.
두 타입은 같은 타입이여도 대입이 되지 않는다.
!!: Null값이 아님을 보증(!!)
- 변수 뒤에 !!를 추가하면 null값이 아님을 보증 -> 아닐 경우 에러

val name:String? = "greenjoa"
val name2:String = name //오류
val name3:String? = name // OK
val name4:String = name!! // OK


변수 및 상수: Variable Nullable
안전한 호출(?.)
- Null 값이 아닌 경우에만 호출

val str:String? = null
var upperCase = if(str!=null) str else null // null


upperCase.toUpperCase() // 에러

-> String값이 될거라고 예상했지만 지금은 null값이기 때문에 멤버함수 호출 불가-> if문으로 해서 해결
upperCase = str?.toUpperCase() // null -> str이 null값이 아니면 뒤에부분 실행해서 반환하고 아니면 그냥 str반환

엘비스(Elvis) 연산자 (?:) -> null일 경우 default값을 지정할때 사용
- Null이 아닌 기본 값을 반환하고 싶을 때 사용
val str:String? = null
var upperCase = str?.toUpperCase() ?:"초기화하시오" --> str이 null값인 경우 "초기화하시오"구분을 넣겠다
// 꼭 ?.이랑같이 쓸 필요는 없음

var upperCase = str?:"초기화하시오"


배열
Array클래스
Array<String>과 같이 제너릭 타입으로 나타냄
- 배열은 크기를 변경할 수 없음
배열 생성 - arrayOf 함수
- val item: Array<Any> = arrayOf(1,"바나나",false)  

//자바에서 object타입에 해당, 꺼낼때는 어떤 type인지 모르니까 typecasting해서 사용하자
- val item:Array<String> = arrayOf("사과", "바나나", "키위") 
빈 배열 생성도 가능
// val arr = arrayOfNulls<Int>(10)

배열 생성 - Array 생성자 // 생성자에는 배열의 크기와 init이라고 하는 함수가 인자로 들어감, 각 원소는 init함수에 의해서 초기화 됨

val item2 = Array<String>(5) { i->(i*i).toString() } // 람다 함수
	item2[0] = item[1]
	for(fruit in item2){
		println(fruit)
}


앞선 것은 제너릭 타입
기본 타입 요소를 저장하는 배열 클래스 // 이것도 array타입, 생성자 둘다 가능하다.

val item: IntArray = intArrayOf(1,2,3,4,5)
val item2: IntArray(5) { j->(j*j) }
	for(num in item2){
		println(num)
}


ByteArray, ShortArray, IntArray, LongArray, FloatArray,... 등등 사용가능

연산자
연산자와 연산자 오버로딩
: 내부적으로 연산자 오버로딩(overloading)한 함수를 사용해서 연산을 처리
a+b // a.plus(b) // a와b의 값을 더한다


=> 6개가 된다는 의미는 다른 타입과는 덧셈 연산이 안된다는것을 의미한다.
연산자 오버로딩을 클래스에 오버로딩해서 만들면 된다.

-단항 연산자
+a, -a, !a, ++a, a++, --a, a--
-복합 대입 연산자
a+=b
a-=b
a*=b
a/=b
a%=b
-비트 연산자 - 오버로딩하고 있지 않음
그냥 함수를 호출해서 사용한다.
8 shr 2
8 shl 4
infix라는 키워드를 가지고 있어서 연산자 처럼 사용할 수 있다.


- 논리 연산자
and, or, not 기호 연산자도 사용가능한데 기능은 살짝 다름
and 연산자는 단락평가를 하지 않는 연산
&&은 단락평가를 적용해서 연산을 한다
- 동등 비교 연산자 
=== : 오버로딩 안됨(참조값이 같은지 판단)

in 연산자
- 특정 객체가 컬렉션에 저장되어 있는지 확인
범위(..) 연산자
- a..b : a에서 b까지의 범위 값이 생성 => a.rangeTo(b) 코드로 변환

val start = LocalDate.now()
val end = start..start.plusDays(15)
println(start.plusWeeks(1) in end) // 있으면 true 없으면 false -> 여기서는 true


- 인덱스 연산자
a[i] -> a.get(i)

- invoke 연산자 : 객체를 통한 함수 호출
invoke 오버로딩하면 클래스의 instance를 함수처럼 사용할 수 있다. 

- 타입 확인 연산자 : is, !is

입출력
- 출력 : println 함수 사용
- 입력 : readline함수-> 한 라인을 입력받음
타입 바꾸고 싶으면 명시적으로 toInt() 이런거 쓰면된다.


아니면 Java패키지 import해서 java.util.Scanner쓰면 된다.
치환 연산자 사용하면 됨(스캐너 객체 생성에만 주의)

print("Enter text: ")
val stringInput = readLine()!!
println("You entered: $stringInput")

//자바의 Scanner 객체 사용(import java.util.Scanner)
val reader = Scanner(System.`in`)
print("Enter a number: ")
var integer:Int = reader.nextInt()
println("You entered: $integer")



난수 발생

// 1. Java의 Random 클래스 사용
// Java.util.random 클래스 import 해야 함
val num = Random().nextInt(10)
// 2. Kotlin에서의 사용
val num = (0..10).random()












728x90
반응형

'App > Android' 카테고리의 다른 글

[4] Kotlin - 클래스, 컬렉션  (0) 2022.03.13
[3] Kotlin : 제어문, 함수  (0) 2022.03.11
[1] Android 소개  (0) 2022.03.08
RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
728x90
반응형

안드로이드는 휴대전화를 비롯한 휴대용 장치를 위한 운영체제와 미들웨어, 사용자 인터페이스 그리고 표준 응용 프로그램(웹 브라우저, 이메일 클라이언트, 단문 메시지 서비스(SMS), 멀티미디어 메시지 서비스(MMS) 등)을 포함하고 있는 소프트웨어 스택이자 모바일 운영체제이다. 

 

Android Architecture

리눅스 커널( != 리눅스 배포판)

- 안드로이드는 리눅스 커널 상에 만들어져 있음

- 하드웨어 구동하는 기능 수행

   - 프로세스, 메모리, 전원, 네트워크, 디바이스 드라이버, 보안 등의 핵심적인 시스템 서비스를 지원함

- 표준 리눅스 유틸리티를 모두 제공하지는 않음

- 안드로이드 커널도 공개되어 있음

 

HAL(Hardware Abstraction Layer)

- 자바 API 프레임워크에서 하드웨어 기능을 이용하는 표준 인터페이스 제공

- 자바 API 프레임워크에서 하드웨어 기기( 카메라, 블루투스 등)를 이용하기 위한 코드가 실행되면 내부적으로 HAL의 라이브러리 모듈이 로딩되어 처리됨.

 

라이브러리

- 장비의 전반적인 속도를 결정하는 중요한 요소임

- 자바가 아니라 C/C++로 작성되어 있으며, 애플리케이션 프레임워크를 통해 사용할 수 있도록 구성되어 있음

- 안드로이드 라이브러리 종류

  - 웹브라우저 및 웹렌더링 엔진 WebKit

  - 미디어 응용 개발 OpenMax AL

  - 임베디드용 c라이브러리 libc

  - 오디오, 비디오 재생을 위한 미디어 지원

  - 3차원 컴퓨터 그래픽스 OpenGL ES

  - 벡터 폰트 출력을 위한 FreeType

  - 데이터베이스 지원을 위한 SQLite

 

안드로이드 런타임 : 코어 라이브러리(자바 라이브러리의 대부분 기능) + Android Runtime

 

애플리케이션 프레임워크

- 안드로이드 API : 안드로이드에서 제공하는 애플리케이션도 애플리케이션 프레임워크의 API 기능을 기반으로 함

- 응용 프로그램들은 하위의 커널이나 시스템 라이브러리를 직접적으로 호출할 수 없으며 API를 통해서 기능을 요청해야 함

 

애플리케이션(응용프로그램)

- 모든 응용프로그램은 애플리케이션 프레임워크의 API를 사용

 

안드로이드 앱은 컴포넌트를 기반으로 함

컴포넌트 : 안드로이드 시스템에서 생성하고, 관리하는 클래스( 앱 내에서의 실행 단위 )

인스턴스화 할 수 있는 4개의 컴포넌트( 이걸 잘 익히면 된다 )

- 액티비티 : 사용자 인터페이스를 구성하는 기본 단위이며, 눈에 보이는 화면 하나가 액티비티이며, 여러 개의 뷰들로 구성, 응용 프로그램은 필요한 만큼의 액티비티를 가질 수 있으며 그 중 어떤 것을 먼저 띄울지를 지정

- 서비스 : UI가 없어 보이지 않으며 백그라운드에서 무한히 실행되는 컴포넌트, 액티비티와 연결해서 사용함

(ex> 미디어 플레이어는 비활성화된 상태라도 노래는 계속 재생되어야 한다)

- 방송수신자(Broadcast Receiver) : 시스템으로부터 전달되는 방송을 대기하고 신호 전달 시 수신하는 역할

(ex> 배터리가 떨어졌다, 사진을 찍었다, 네트워크 전송이 완료되었다 같은 신호 받음)

- 콘텐츠 제공자(Content Provider) : 다른 응용 프로그램을 위해 자의 데이터를 제공, 응용 프로그램 간에 데이터 공유

Manifests : XML 파일로 구성 컴포넌트, 앱에 대한 전반적인 정보
Java : 소스 파일들이 저장
generatedJava : Java 관련 라이브러리 (터치할일 거의 x)
Res : 외부의 다양한 리소스들 저장하기 위한 폴더
Gradle scripts : Gradle이 빌드시에 필요한 스크립트(Java는 Marven, 안드로이드는 gradle)

-> 코드와 리소스를 분리한 것이 특징이다.

728x90
반응형

'App > Android' 카테고리의 다른 글

[3] Kotlin : 제어문, 함수  (0) 2022.03.11
[2] Kotlin  (0) 2022.03.08
RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
Intent  (0) 2021.08.23
728x90
반응형

리스트뷰는 유사하게 반복되는 뷰를 그리기 위한 도구이다. 리스트뷰는 3가지 방법으로 그릴 수 있다.

1. AddView

AddView는 실제로 리스트뷰를 그리기위해서 잘 사용되지는 않는다. AddView는 Item을 담을 xml을 만들어 주고 그 xml에 내용을 채워주어 Container View에 더해준다. 이 작업을 계속 반복한다.

2. ListView

ListView는 리스트로 만들고 싶은 아이템의 리스트를 준비한 뒤 Inflater로 아이템 하나에 해당하는 뷰를 만들어 준다. 여기서 만든 뷰를 컨테이너 뷰에 붙여준다. Adapter를 사용하게 된다. AddView와의 다른점은 AddView는 리스트의 갯수와 상관없이 한번에 다 그리고 ListView는 보여지는 부분만 그리고 필요한 경우(스크롤을 내릴때) 더 그리게 된다.

3. RecyclerView

RecyclerView의 장점은 ListView의 개선판이다. ViewHolder를 포함하기 때문에 RecyclerView를 사용하면 무조건 ViewHolder를 사용하게 된다. 그리고 LayoutManager를 관리할 수 있다. LayoutManager는 Linear, Grid, StaggerGrid로 활용할 수 있어 유연하게 활용 가능하다. 

https://stackoverflow.com/questions/34216890/android-difference-between-gridlayout-and-staggered-gridlayout

 

Android - Difference between Gridlayout and Staggered Gridlayout

I am working in android material design api & want to display some data in grid format. I tried both GridLayout and StaggeredGridlayout and both look same. For general information, i want to as...

stackoverflow.com

앞으로 개발할때 ListView를 만들경우 RecyclerView를 사용하고 이전에 만들어진 ListView, AddView는 알아야 유지보수 가능하기 때문에 배워야 한다.

 

(RecyclerView를 사용하려면 먼저 dependencies에서 recyclerview를 import시켜줘야한다.)

1. 메인엑티비티에 Recyclerview 추가

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

2. ItemView 레이아웃 추가

3. Recyclerview Adapter 구현-> class를 새로 만들어서 onCreate에 붙여준다.

- RecyclerView.Adapter를 상속하여 구현

- 오버라이드 필요한 메서드

onCreateViewHolder(ViewGroup parent, int viewType) viewType 형태의 아이템 뷰를 위한 뷰홀더 객체 생성.
onBindViewHolder(ViewHolder holder, int position) position에 해당하는 데이터를 뷰홀더의 아이템뷰에 표시.
getItemCount() 전체 아이템 갯수 리턴.

흐름
1) onCreateViewHolder에서 view를 만든것을 viewholder에 넣어준다(아이템 하나씩)
2) viewholder에서 init으로 carname, carengine만 설정
3) onBindViewHolder에서 setText로 내용 설정

class RecyclerViewAdapter(
    val itemList:ArrayList<CarForList>,
    val inflater:LayoutInflater
):RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){

    inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
        val carName:TextView
        val carEngine:TextView

        init{
            carName=itemView.findViewById(R.id.car_name)
            carEngine=itemView.findViewById(R.id.car_engine)
            itemView.setOnClickListener {
                val position:Int = adapterPosition
                val engineName = itemList.get(position).engine
                Log.d("engine",engineName)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = inflater.inflate(R.layout.item_view,parent,false)
        return ViewHolder(view)
    }//ViewHolder생성되는 함수

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.carName.setText(itemList.get(position).name)
        holder.carEngine.setText(itemList.get(position).engine)
    }//생성된 뷰홀더에 데이터를 바인딩 해주는 함수

    override fun getItemCount(): Int {
        return itemList.size
    }
}

4. Adapter, LayoutManager 지정

- 어뎁터에 대한 객체와 레이아웃매니저의 객체를 생성한 다음, 각 객체를 setAdapter() 메서드와 setLayoutManager() 메서드를 통해 RecyclerView에 지정한다.

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

        val carList = ArrayList<CarForList>()
        for(i in 0 until 100) {
            carList.add(CarForList("" + i + "번째 자동차", "" + i + "순위 엔진"))
        }
        val adapter = RecyclerViewAdapter(carList, LayoutInflater.from(this@RecyclerViewActivity))
        recycler_view.adapter=adapter
        recycler_view.layoutManager=LinearLayoutManager(this@RecyclerViewActivity)
        // recycler_view.layoutManager=GridLayoutManager(this@RecyclerViewActivity,2)
    }

ViewHolder : 뷰객체를 기억하고 있을 객체
Adapter : 모든 아이템이 담긴 리스트를 RecyclerView에 Binding 시켜주기 위한 사전 작업이 이루어 지는 객체
LayoutManager: 스크롤 위아래로 할지, 좌우로 할지 이런거 결정

728x90
반응형

'App > Android' 카테고리의 다른 글

[2] Kotlin  (0) 2022.03.08
[1] Android 소개  (0) 2022.03.08
Fragment  (0) 2021.08.23
Intent  (0) 2021.08.23
첫 프로젝트 만들기  (0) 2021.03.07
728x90
반응형

Fragment는 Activity의 파트를 나눈것들이다. Activity가 너무 길어지면 관리 포인트가 많아 관리가 어려워지기 때문에 Fragment를 사용해서 나누어 해결한다. Activity가 라이프사이클이 있는 것처럼 Fragment도 라이프사이클이 있다. 

 

Fragment 사용방법
1. XML에 ViewComponent로 추가한다
2. 코드로(동적)으로 추가한다

 

Fragment를 만들기 위해서 class를 만들어 fragment()를 상속받아 준다. (Activity 만들때는 AppCompatActivity()를 상속받은 것처럼)

class FragmentOne:Fragment()

override method를 통해서 onAttach(), onCreate(), onCreateView(), onViewCreated(), onActivityCreated(), onStart(), onResume(), onPause(), onStop(), onDestroyView(), onDetach()를 만들어주었다.

 

xml에서 Fragment를 사용해서 넣어주면 된다.

<fragment
        android:id="@+id/fragment_one"
        android:name="com.example.myapplication.FragmentOne"
        android:layout_width="match_parent"
        android:layout_height="300dp"/>

id와 name을 꼭 넣어주어야 한다. name은 fragment태그에 들어갈 내용을 의미한다. FragmentOne 클래스를 넣어준다.

FragmentOne에서 List를 그려야 한다. LifeCycle중에서 onCreateView()를 이용해서 그린다. onCreateView()는 fragment가 interface를 처음으로 그릴때 호출된다. Activity는 setContentView가 책임졌다면 fragment는 onCreateView()가 책임진다.

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.d("life_cycle","F onCreateView")
        // fragment 가 인터페이스를 처음으로 그릴 때 호출된다.
        // inflater -> 뷰를 그려주는 역할
        // container -> 부모뷰 달라붙을 곳
        return inflater.inflate(R.layout.fragment_one,container,false)
    }

fragment는 setContentView와는 달리 inflater와 container가 들어온다. inflater는 뷰를 그려주는 역할, container는 부모뷰를 의미한다. inflater중에 inflate함수가 있다. xml으로 fragment_one을 만들고 붙여주면 된다.

 

이번엔 Fragment를 동적으로 추가해보자. 버튼을 눌러서 fragment를 달아주는 모습을 보여주자. Fragment를 동적으로 추가하기 위해서는 FragmentManager의 도움을 받아야한다. supportFragmentManager는 Activity가 가지고 있다. supportFragmentManager를 가지고 와서 FragmentManager에 넣어준다.

 Transaction이라는 것도 만들어주어야 한다. Transaction은 작업의 단위이고 시작과 끝이 있다. fragmentTransaction에서 beginTransaction()을 실행해주고 할일(replace/add)를 입력해준다. 끝은 commit()이라는 것으로 명령해준다.

	val fragmentOne:FragmentOne= FragmentOne()
	val button:Button=findViewById(R.id.button)
        button.setOnClickListener {
            // fragment를 동적으로 작동하는 방법 -> 코드 입력
            // fragment 붙이는 방법 replace/add
            val fragmentManager:FragmentManager = supportFragmentManager

            // Transaction
            // 작업의 단위 -> 시작과 끝이 있다
            val fragmentTransaction=fragmentManager.beginTransaction()
            fragmentTransaction.replace(R.id.container,fragmentOne)

            fragmentTransaction.commit()
            // 끝을 내는 방법
            // commit -> 시간 될 때 해
            // commitnow -> 지금 당장해
        }

 

Fragment를 떼는 방법

	val fragmentOne:FragmentOne= FragmentOne()
	val button2:Button=findViewById(R.id.button2)
        button2.setOnClickListener {
            // fragment remove/detach 하는 방법
            val fragmentManager:FragmentManager=supportFragmentManager
            val fragmentTransaction=fragmentManager.beginTransaction()
            fragmentTransaction.detach(fragmentOne)
            fragmentTransaction.commit()
        }

detach/remove : remove는 다시 붙일 수 있고 detach는 안됨.

 

Fragment에 data를 넣어주는 방법

데이터 전달 방법
- Activity -> Fragment : argument bundle
- Fragment -> Activity : 자체 구현(리스너 구현)

 

budle이라는 것을 만들어서 Fragment에 끼워 넣어줘야 한다.

	// fragment 에 data 를 넣어주는 방법
        val bundle:Bundle = Bundle()
        bundle.putString("hello","hello")
        fragmentOne.arguments=bundle

(bundle은 type을 고려해주어야 한다)

putString 해주었으면 FragmentOne에서 꺼내주면 된다.

 override fun onActivityCreated(savedInstanceState: Bundle?) {
        Log.d("life_cycle","F onActivityCreated")
        val data = arguments?.getString("hello")
        // Log.d("data",data)
        super.onActivityCreated(savedInstanceState)
    }

 

Fragment -> Activity 데이터 전달은 리스너를 만들어서 구현한다.

    interface OnDataPassListener{
        fun onDataPass(data:String?)
    }
    lateinit var dataPassListener:OnDataPassListener
    override fun onAttach(context: Context) {
        super.onAttach(context)
        dataPassListener = context as OnDataPassListener
    }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Log.d("life_cycle","F onViewCreated")
        super.onViewCreated(view, savedInstanceState)
        // Activity의 OnCreate에서 했던 작업을 여기에서 한다
        val pass:Button=findViewById(R.id.pass)
        pass.setOnClickListener {
            dataPassListener.onDataPass("Good Bye")
        }
    }

이렇게 하고 FragmentActivity에 달아주면 된다.

class FragmentActivity : AppCompatActivity(),FragmentOne.OnDataPassListener {

    override fun onDataPass(data: String?) {
        Log.d("pass",""+data)
    }

 

728x90
반응형

'App > Android' 카테고리의 다른 글

[1] Android 소개  (0) 2022.03.08
RecyclerView  (0) 2021.08.25
Intent  (0) 2021.08.23
첫 프로젝트 만들기  (0) 2021.03.07
안드로이드(Android) 개요와 설치  (0) 2021.03.03
728x90
반응형

Intent 라는 단어의 사전적 의미는 의도, 요구, 의사 전달, 요청 이라는 뜻이다. 

안드로이드 앱 프로그래밍에서 Intent는 Activity와 Activity , Android System과 내 App(전화 ex.배달앱에서 전화바로 연결하는 것) , 다른 App과 내 App 연결(ex. 결제할 때 pay화면 연결) 할 때 사용한다. 예를 들어 버튼을 누르면 다른 새로운 화면(새로운 Activity)가 나오는 것을 intent로 처리를 할 수 있다. 요청의 종류에는 두 가지가 있다. 전달만 하는 요청이 있고 리턴을 받는 요청이 있다.

 

Intent는 지금 화면이 사라지고 새로운 화면을 불러오는 것이다. Intent를 코드 상으로 활용하려면 intent라는 클래스를 만들어주면 된다. 

var intent = Intent(this@Intent1, Intent2::class.java)

1. activity를 전환하려면 Intent에는 처음 변수에는 context(여기서는 Intent1), 두 번째 변수에는 이동할 대상 여기서는 Intent2가 된다.

- Context : context는 문맥을 의미한다. Activity가 가지고 있는 주변 정보라고 생각하면 된다. class가 가지고 있는 정보랑 유사하다. 여기서 this@Intent1이 아닌 this만 입력하여도 상관없다. 여기서는 가능하지만 다른 곳에서는 에러가 날 수 도 있으므로 context를 넣어야 하는 곳에는 this@(현재 Activity)를 넣어주자.

- ::class.java를 꼭 넣어줘야 Intent2라는 것을 알 수 있다.

 

2. Intent를 만들었으면 Intent를 보내야 한다. 만든 변수를 startActivity안에 넣어주자.

startActivity(intent)

 

Intent에 정보를 담아 보내는 방법 (Key, Value 방식으로 전달)

Intent1에서 보내주므로 Intent1에 putExtra를 해서 보내고, Intent2에서 getExtra함수를 통해 받으면 된다.

intent.putExtra("number",1)
val number1 = intent.getIntExtra("number1",0)

getIntExtra는 첫번째 파라미터는 찾는 key값, 두번째는 없을때 대비해서 default값을 넣어준다.

 

Intent2에 putExtra를 apply를 사용해 묶어서 사용할 수 있다.

intent2.apply
{
    this.putExtra("number1",1)
    this.putExtra("number2",2)
}

 

Intent2에서 Intent1으로 돌려보내기

1. Intent에 결과를 담는다.

val resultIntent= Intent()
resultIntent.putExtra("result",result)
setResult(Activity.RESULT_OK,resultIntent)

setResult에는 RESULT_OK랑 전달해줄 값을 순서대로 넣는다. RESULT_OK는 잘 전송한다는 뜻이다(숫자 적어주면 됨)

Activity를 종료하려면 finish()함수를 사용하면 된다. Intent2를 종료시켜 Intent1을 보여주면 된다.

 

2. Intent1에서 결과 받기

onActivityResult 함수를 override해준다. 

전달만 하는 요청은 startActivity()로 요청하고, 리턴을 받는 요청은 startActivityForResult이다.

startActivityForResult(intent2,200)

파라미터를 intent 넣어주고 requestcode를 넣어줘야 된다. Intent에 요청하는 것이 여러개 일수도 있기 때문에 구별하기 위해서 requestCode를 넣어준다. 이름을 숫자로 적어준다.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

        if(requestCode==200){
            Log.d("number",""+requestCode)
            Log.d("number",""+resultCode)
            var result = data?.getIntExtra("result",0)
            Log.d("number",""+result)
        }

        super.onActivityResult(requestCode, resultCode, data)
    }
728x90
반응형

'App > Android' 카테고리의 다른 글

RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
첫 프로젝트 만들기  (0) 2021.03.07
안드로이드(Android) 개요와 설치  (0) 2021.03.03
Kotlin은 무엇일까 + Kotlin에서의 변수와 함수  (0) 2021.03.03
728x90
반응형

[Create New Project]를 선택하면 새로운 안드로이드 프로젝트를 만들기 위한 대화 상자가 순서대로 표시된다. 

Empty Activity를 선택하여 만들었다.

 

이름은 Hello로 하고 언어는 Java를 이용하여 만들었다. 

 

패키지 이름이란?

앱을 구분하는 고유의 값으로 앱이 단말에 설치되었을 때 다른 앱과 구분될 수 있는 역할을 한다. 패키지 이름은 다른 패키지 이름과 충돌하지 않게 지어주고 실무에서는 인터넷 사이트 주소처럼 짓는 경우가 많다

 

안드로이드 스튜디오 창이 열릴 때까지 시간이 걸린다. 

상태 바에 'Gradle build finished'로 시작한는 문장과 함께 화면이 모두 나타날 때까지 기다린다.

 

1. MainActivity.java

 새로운 안드로이드 프로젝트에서는 자바 언어를 사용하기 때문에 java라는 확장자를 가진 파일이 만들어지며 표준 자바의 문법으로 작성되어 있다. 

 

2. activity_main.xml

왼쪽의 하얀 화면은 실제 스마트폰 화면에 나타날 디자인 화면이고 오른쪽의 남색 화면은 화면의 구성 요소만을 보여주는 청사진 화면이다. 각각 Design과 Blueprint 항목이다. Blueprint 화면이 필요한 이유는 화면 안의 요소가 서로 겹쳐 있을 때 요소를 투명하게 보고 작업할 수 있어 유용하다.

 

3. 에뮬레이터로 Hello World 앱 실행하기

 안드로이드 기기가 없어도 컴퓨터에서 에뮬레이터와 가상 단말을 이용하면 앱을 실행할 수 있다. 에뮬레이터는 가상 단말을 실행하기 위한 프로그램인데 이 프로그램은 안드로이드 스튜디오를 설치할 때 이미 설치되어 있다. 즉, 가상 단말(Virtual Device)만 만들면 된다. 

 

 3.1 가상 단말 만들기

 안드로이드 스튜디오 오른쪽 상단에 있는 아이콘 중 [AVD Manager] 아이콘을 클릭하면 가상 단말을 만들거나 실행할 수 있는 가상 단말 관리 화면(Android Virtual Device Manager)이 나타난다.

[+Create Virtual Device] 버튼을 눌러 새로운 가상 단말을 만든다.

Select Hardware 창이 나타나면 여기에서 새로운 가상 단말의 하드웨어를 선택할 수 있다. 기본 값인 Pixel 2를 그대로 두고 [Next] 버튼을 누른다.

 

그러면 System Image 창이 나타난다.

여기서는 가상 단말을 실행할 때 필요한 이미지를 선택할 수 있다. 이미지란 단말기 하드웨어의 종류에 따라 달라지는 것으로 하드웨어를 실행하기 위한 정보를 담고 있는 하나의 파일이라고 생각하면 된다. 가장 위에 있는 R을 사용하겠다. 

 

ABI란?

 Application Binary Interface의 약자로 안드로이드 CPU 칩과 시스템 사이의 상호 작용 방법을 기술한 인터페이스를 의미한다. 안드로이드 단말의 CPU 칩은 제조사마다 다르기 때문에 제조사에 맞는 ABI를 선택해야 한다. 가장 대표적인 것은 ARM, MIPS, x86이며 나는 x86을 사용한다.

 ABI를 x86으로 지정하면 PC의 가상화 기술을 허용해야 한다. ABI 값을 x86으로 선택하여 가상 단말을 실행하면 가상화 기술(Virtualization Technology)을 사용할 수 없다는 오류 메시지가 나타나는 경우가 많다. 이 메시지는 x86으로 만들어진 가상 단말이 실행될 때 가상 단말을 실행하는 PC에서 가상화 기술을 허용하지 않아 발생한 것이다. 

 이 문제를 해결하려면 PC의 바이오스에서 Virtualization Technology라는 항목을 Enable로 바꿔주어야 한다. PC의 바이오스로 들어가는 방법은 PC가 켜질 때 F8이나 ESC키를 누르면 된다.

 

에뮬레이터 실행 과정을 거친 후 안드로이드 단말의 홈 화면이 나타난다. 이제 만든 앱을 바로 실행해보겠다.

 

3.2 에뮬레이터를 사용하여 앱 실행하기

 shift+F10을 눌러 앱을 실행하면 된다.

 

앱이 실행되면 안드로이드 스튜디오 아래에 있는 [Logcat] 탭에 로그가 출력된다.

 

4. Hello 프로젝트 하나씩 바꾸어보기

 

 앞에서 만든 앱은 Hello World! 라는 메시지를 띄우는 모양의 앱이다. 이 앱은 비록 단순하지만 실제 안드로이드 기기에서도 실행되는 진짜 앱이다. 앱을 실행하면 나타나는 Hello World는 입력한 적도 없는데 화면에 나타났다. 

 

4.1 MainActivity.java 자세히 살펴보기

package com.example.hello;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

코드를 보면 표준 자바나 다른 언어에서 애플리케이션의 시작점 역할을 하는 main 함수가 없다. 이것으로 안드로이드에서는 'main 함수가 아닌 다른 함수가 시작점의 역할을 한다.' 고 추측할 수 있다. 

 

그러면 onCreate() 함수를 보자. onCreate() 함수 안의 첫번째 줄에서는 super라는 키워드를 사용하여 onCreate()함수를 호출한다. super 키워드는 상속을 받은 클래스에서 부모 클래스를 가리킬 때 사용한다. 즉, 이 코드는 부모 클래스에 있는 onCreate() 함수를 호출하는 것이고 부모 클래스의 onCreate() 함수는 이 클래스의 기능과 직접적인 관련은 없으므로 화면의 메시지를 보여주는 기능과는 상관없다.

 그럼 setContentView(R.layout.activity_main)을 보자. setContentView()함수는 화면에 무엇을 보여줄 것인지를 설정해주는 역할을 하고 R.layout.activity_main은 화면의 구성 요소에 대한 정보라는 것만 이해하고 넘어가자. 

 

4.2 activity_main.xml 자세히 살펴보기

 activity_main.xml은 [res]폴더 안에 있다. [res]폴더 안에 [layout]폴더 안에 있다. MainActivity.java에서 보았던 파라미터인 R.layout.activity_main이라는 이름과 비슷하다. 즉, MainActivity.java와 activity_main.xml이 연결되어 하나의 화면을 보여주는 것이다. 

 

 activity_main.xml파일을 더블클릭하여 열어보면 앱의 첫 화면 자체를 의미하는 것을 알 수 있다.

 

 activity_main.xml 화면 아래에 있는 [Text]탭과 [Design] 탭을 보면 고칠 수 있는 텍스트 화면과 화면 구성 요소를 마우스를 이용해 넣을 수 있는 디자인 화면이 나타난다.

 

5. 버튼 누르면 메시지 출력하기

 Design 탭에 들어가면 많은 것들이 있다. Text, Buttons, Widgets 등등.. 

 먼저 디자인탭 상단에 자석에 금지 표시를 한 번 클릭하여 지워주자.

 그리고 Common 탭에서 Button을 사용하여 Button을 화면 중앙에 두자(원래 있던 Text는 delete로 삭제 가능하다)

 

우리가 만든 버튼은 activity_main.xml 파일 안에 있다. 이 버튼과 자바 소스(Main-Activity.java)는 분리되어 있다. 그래서 activity_main.xml에 추가한 버튼을 MainActivity.java에 연결해야 한다. 그래야 버튼에서 발생한 클릭 이벤트를 자바 소스에서 처리할 수 있다. 이 과정은 다음과 같다.

 

1) XML 레이아웃 파일의 버튼에 onClick 속성 값 넣기 : activity_main.xml 파일에 들어 있는 버튼에 onClick 속성 값으로 클릭 이벤트를 처리할 함수 이름을 입력한다. 이때 이 함수 이름은 소스 코드(MainActivity.java)에 들어 있는 함수 이름을 그대로 사용한다. 

 

2) 소스 파일에 이벤트 처리 함수 추가하기 : MainActivity.java 파일을 열고 XML에서 지정한 함수를 추가한다. 이 함수의 이름은 위에서 넣은 onClick 속성 값과 같아야 한다. 

 

Button을 연결할려면 activity_main.xml에서 Button에 속성값을 추가하여야 된다. 

즉, 이 버튼을 누르면 자바 소스에서 onButton1Clicked 함수를 찾아 실행하게 된다. 이제 소스 코드에 onButton1Clicked함수를 추가하면 된다. 그런데 소스 코드를 수정하기 전에 먼저 해야 할 일이 있다. 자바에서는 어떤 클래스를 사용할 때 import 구문을 추가해야 하는데 이것을 일일이 입력하는 것은 귀찮아서 import 구문을 자동으로 넣을 수 있는 기능을 제공한다. 

 

 안드로이드 스튜디오 메뉴에서 [File->Settings]를 선택한다. [Settings] 대화상자가 나타나면 [Editor -> General -> Auto Import]를 선택한다. 오른쪽 설정 화면에서 Add unambiguous imports on the fly 와 Optimize on the fly 항목을 체크한 후 [OK]버튼을 클릭한다. 

 

그러면 자동으로 import된다. 이후에 MainActivity.java에 다음과 같은 코드를 입력해준다.

package com.example.hello;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onButton1Clicked(View v){
        Toast.makeText(this,"확인1 버튼이 눌렸어요",Toast.LENGTH_LONG).show();
    }
}

안드로이드에서 Toast(토스트)는 작고 간단한 메시지를 잠깐 보여주는 역할을 한다. 

makeText() 함수는 Toast라는 클래스에 포함되어 있다. 그래서 이 함수를 사용하려면 Toast 클래스를 import해야 한다. 만약 Toast 클래스가 import되지 않으면 안드로이드 스튜디오가 자동으로 코드를 체크하여 오류를 표시한다.

import 오류를 해결하려면 Alt+Enter를 몇 번 눌러도 된다. 

 

이렇게 실행하면 확인1 버튼을 누르면 "확인1 버튼이 눌렸어요" 라는 창이 뜨게 된다.

 

6. 버튼 여러 개 추가하기

 

확인1 버튼 아래에 버튼 하나를 추가하자. 버튼 추가하는 방법은 위와 같이 Palette에서 Common 탭에서 버튼을 끌어오면 된다. 물론 자석 표시는 대각선으로 안되어있을테니 그냥 끌어오면 된다.

 

새로 만든 버튼을 보면 테두리에 왼쪽 오른쪽 동그라미에는 파란색으로 채워져 있는데 위,아래쪽 테두리에 보이는 동그라미는 비어있다.

 

 새 버튼 테두리 위쪽에 있는 빈 동그라미를 누르고 확인 1 버튼의 아래쪽 테두리에 끌어다 놓으면 연결선이 표시되며 자동으로 달라붙는다.

 

버튼을 클릭한 상태에서 오른쪽 Attributes 영역에서 텍스트 속성 값을 '네이버 접속하기' 로 onClick 속성 값은 'onButton2Clicked'를 입력하자.

 

그리고서는 MainActivity.java에 onButton2Clicked에 해당하는 코드를 입력해주면 된다.

 

(버튼3까지 말들어서 실행해 보자)

 

public void onButton2Clicked(View v){
        Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://m.naver.com"));
        startActivity(myIntent);
}

public void onButton3Clicked(View v){
    Intent myIntent = new Intent(Intent.ACTION_VIEW,Uri.parse("tel:010-10000-1000"));
    startActivity(myIntent);
}

이렇게 만들면 버튼2를 누르면 네이버에 접속이 되고, 버튼3을 누르면 전화를 걸 수 있는 화면으로 바뀐다.

 

단 몇줄의 코드를 입력하여 여러 기능을 추가했다. 이것을 가능하게 하는 것이 바로 '인텐트(Intent)'이다. 인텐트는 내가 하고자 하는 행위를 의미한다. 쉽게 말해 인텐트를 사용하면 애플리케이션 구성 요소 간에 데이터를 전달하거나 실행하려는 기능이 무엇인지 안드로이드 플랫폼에 알려줄 수 있다.

 

웹브라우저는 안드로이드 단말에 기본으로 제공되는 앱이니까 직접 만든 앱에서 안드로이드 단말에 '웹페이지를 띄워보고 싶어요'라고 편지를 쓰면 안드로이드 단말은 그 편지를 웹브라우저에 전달한다. 그러면 웹브라우저가 그 편지를 보고 그 내용에 맞는 웹페이지를 띄우는 것이다.

 

기억해야 될 것들은 다음과 같다.

 

1. 프로젝트 만들기 : 안드로이드 스튜디오에서 안드로이드 프로젝트를 만들 수 있다.

 

2. setContentView() : 화면에 무엇을 보여줄지 결정하는 함수(메서드)이다. 

 

3. R.layout.activity_main : 화면에 보여줄 대상이 되는 XML의 위치를 지정한다.

 

4. /app/res/layout/activity_main.xml : 자바 소스에서 R.layout.activity_main이라고 입력하여 가져올 수 있는 프로젝트 안의 파일이며, 화면을 구성할 때 사용한다.

 

5. text 속성 : 화면에 보이는 글자를 변경할 때 사용하는 속성이다.

 

6. onClick 속성 : 버튼을 클릭했을 때 어떤 메서드를 실행할 것인지 간단하게 지정할 수 있는 속성이다.

 

7. Intent : 어떤 기능을 실행할 것인지 지정할 때 사용한다.

 

8. Toast : 화면에 잠깐 보였다 없어지는 메시지를 간단하게 보여주고 싶을 때 사용한다.

728x90
반응형

'App > Android' 카테고리의 다른 글

RecyclerView  (0) 2021.08.25
Fragment  (0) 2021.08.23
Intent  (0) 2021.08.23
안드로이드(Android) 개요와 설치  (0) 2021.03.03
Kotlin은 무엇일까 + Kotlin에서의 변수와 함수  (0) 2021.03.03

+ Recent posts