💻STUDY/ANDROID STUDY

[Android-Kotlin] 4주차

coldNoodlePigeon 2022. 5. 2.
  • 한빛미디어의 『이것이 안드로이드다 with 코틀린』 유튜브 강좌를 듣고 정리한 내용입니다 

 

클래스 

 

package com.example.aclass

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

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

        //클래스의 사용
        //1.초기화를 사용하는 방법
        var cls=클래스() //메모리에 로드되어 있는 클래스: 인스턴스

        cls.variable
        cls.function() //도트로 변수와 함수 사용 가능

        //2.companion object로 만들어 사용하는 방법
        Log.d("태그","메시지")

    }
}

class Log{
    companion object{ //class 내부의 property나 function을 초기화없이 사용 가능
        var variable="난 누구"
        fun d(tag:String,msg:String){
            print("[$tag] : $msg")
        }
    }
}

//변수(property)와 함수(method)의 모음
class 클래스{
    init{
        //클래스를 초기화하면 호출된다.
    }

    var variable:String=""//변수- property

    fun function(){ //함수-method

    }
}

클래스는 변수(property)와 함수(method)의 모음이다. 

 

 

다음은 클래스의 상속에 대해 공부해보았다. 

package com.example.aclass

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

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

        var child=Child()
        child.showMoney()

    }
}

//상속을 사용하는 이유
//1.기존의 작성된 코드를 재활용하기 위해서
//2. 코드를 재활용하는데 더 체계적으로 계층구조를 사용하기 위해서

open class Parent{ //open: 상속할 수 있는 클래스라는 의미
    var money=5000000
    var house="강남 200평 아파트"
}

class Child:Parent(){ //클래스의 변수 사용하기 위해선 초기화가 필요
    //상속받으면 부모클래스의 property와 method를 내것처럼 사용이 가능
    fun showMoney(){
        Log.d("클래스","money=${money}")
    }
}

위와 같은 형식으로 클래스를 상속받아 마치 자기것처럼 사용하는 것이 가능하다. 위 코드를 실행했을떄는 다음과 같은 결과를 Logchat을 통해 확인할 수 있었다. 

 

 

다음으로 공부한건 오버라이드(override)이다.

 

package com.example.aclass

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

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

        var parent=Parent()
        parent.showHouse()

        var child=Child()
        child.showHouse()

    }
}


open class Parent{ //open: 상속할 수 있는 클래스라는 의미
    var money=5000000
    open var house="강남 200평 아파트"

    open fun showHouse(){ //함수가 재정의(오버라이드)될 경우 open 키워드 필요
        Log.d("클래스","house=${house}")
    }
}

class Child:Parent(){ 
    
    override var house="강남 10평 오피스텔"

    fun showMoney(){
        Log.d("클래스","money=${money}")
    }

    override fun showHouse(){ //override: 함수를 재정의함. 재정의하는 경우 override 키워드 필요!
        Log.d("클래스","house=${house}")
    }
}

오버라이드는 말그대로 상속받은 클래스에서 함수를 재정의하는 것으로, 재정의하기 앞서서 재정의할 함수의 앞에 open이라는 키워드를 붙여줘야한다. 재정의할 변수 또한 마찬가지이다.

그리고 재정의하는 경우 override라는 키워드를 붙여서 재정의해야 한다. 위의 코드는 showHouse() 함수를 재정의하였다. 메인 코드를 실행하면 다음과 같은 결과가 Logchat에 출력된다. 

 

다음으로 공부한 것은 오버로드이다. 

package com.example.aclass

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

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

        var son=Son()
        var result=son.getNumber("엥")

    }
}

//오버로드 
class Son{
    fun getNumber():Int {//아무것도 매개변수로 들어오지 않으면 1을 return
        return 1
    }

    fun getNumber(param:String):Int{ //string 매개변수가 입력되면 2를 return
        return 2
    }
}

같은 이름의 함수이지만, 아래의 함수의 경우 String형의 매개변수가 들어오게 되면 2를 리턴하는 함수고, 아무것도 매개변수로 들어오지 않으면 1을 리턴하는 기능을 한다. 이런 것을 오버로드라고 한다. 

 

 

 NULL 값을 안정적으로 처리하는 방법 

 

package com.example.aclass

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

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

        var myName:String="김진영"
        var number:Int?=null //1. nullable:null을 넣을 수 있는 상태
        var newVariable: Activity?=null //변수가 생성될지 안될지 아직 확신 못하는 경우 null로 초기화.
        //null이라는 것도 생성되지는 않았지만 메모리에 시스템적으로 존재함.

        Log.d("null test","문자열의 길이는=${myName.length}}")

        //null에는 plus라는 기능이 만들어져 있지 않음.
        number.plus(50) //Null Pointer Exception 발생 ->그래서 null safety 등장

        var result= number?.plus(50)?:51
        //2. Safe Call: ?를 붙여줌. ->?다음을 실행하지 않음. 에러 발생x
        // ?: -> Elvis Expression: null값이 들어갈 경우 default값으로 51을 정해줌
        var result=result.plus(53)


        var number2:Int=30
        var result2= number2.plus(50)

    }
}

총 3가지 방법.

1. nullable 

2. Safe Call 

3. Elvis Expression 

 

 

 

 

코틀린을 위한 기본 문법: 지연초기화 

package com.example.aclass

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {


    //지연초기화: 메모리가 낭비되는 것을 막기 위한 기술
    //lateinit var 변수명:타입 or 클래스명
    //보통 클래스들을 지연초기화하고 싶을 때 사용함.
    lateinit var person:Person //코드 상에서 이 변수를 메인함수 내에 넣을 예정임을 알려줌.
    //주의점: 기본형(int,long,float,double)에는 사용할 수 없음.

    //var 변수명 by lazy{변수에 들어갈 클래스생성자 or 값}
    //한번 값을 넣고 바꾸는 경우가 없을때 lazy 사용
    val age by lazy{Person()}
    // val age by lazy{21} <클래스생성자 대신 값을 넣을 수도 있음. 

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

        person=Person()
    }
}

class Person{
    var name=""
    var age=""
    var address=""
    var tel=""
}

메모리가 낭비되는 것을 막기 위해 main함수에 변수를 사용하기 전에 미리 처리해주는 것. 

 

 

코틀린을 위한 기본 문법: 스코프함수 

 

1.run 사용법 

package com.example.aclass

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {


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

    }

    //스코프 함수
    //run,let,apply,also
    //with (사용법이 조금 다름!)

    //1.run
    fun studyRun(){
        val phones= mutableListOf("010-1234-5678","010-3456-7898","010-5678-1234")
        val list= mutableListOf(1,2,3,4,5,6,7,8,9)
        val names= mutableListOf("scott","kelly","michael")

        phones.run{ //반복되는 것을 축약하는 역할.
            //스코프 함수를 사용하지 않는다면 phones.add()를 반복해서 써야함.
            add("010-2345-1234")
            add("010-5663-1221")
        }
    }
}

run은 반복되는 것을 축약하는 역할을 한다. 

 

2. let,apply,also 사용법

package com.example.aclass

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {


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

        studyRun()
    }

    //스코프 함수
    //run,let,apply,also
    //with (사용법이 조금 다름!)


    fun studyRun(){
        val phones= mutableListOf("010-1234-5678","010-3456-7898","010-5678-1234")
        val list= mutableListOf(1,2,3,4,5,6,7,8,9)
        val names= mutableListOf("scott","kelly","michael")

        val seoulPeople=SeoulPeople()

        //1.run을 사용
        //resultRun라는 변수에 반환해줄 수 있다.

        val resultRun= seoulPeople.persons.run{ //간단하게 표현이 가능.
            add(Person("scott","010-1234-5678",19))
            add(Person("kelly","010-3456-7898",20))
            add(Person("michael","010-5678-1234",21))
            11
        }


        //2.let을 사용: 예약어를 사용하고 싶을때
        //밑의 경우는 it을 사용하는 경우이고
        seoulPeople.persons.let{
            it.add(Person("scott","010-1234-5678",19))
        }



        //아래처럼 "어디"에 추가하는지를 명시적으로 보여주고 싶을때 예약어를 붙여줄 수 있다. (run에서는 사용 불가능)
        val resultLet= seoulPeople.persons.let{ persons->
            persons.add(Person("scott","010-1234-5678",19))
        }

        //3. apply (run과 사용법이 똑같음)
        val resultApply=seoulPeople.persons.apply{
            add(Person("scott","010-1234-5678",19))
            add(Person("kelly","010-3456-7898",20))
            add(Person("michael","010-5678-1234",21))
        }

        Log.d("스코프함수","resultApply=$resultApply")


        //4.also (let과 사용법이 똑같음)
        val resultAlso=seoulPeople.persons.also{ persons->
            persons.add(Person("scott","010-1234-5678",19))
        }

    }
}

class SeoulPeople{
    var persons= mutableListOf<Person>()
    init{
        persons.add(Person("scott","010-1234-5678",19))
        persons.add(Person("kelly","010-3456-7898",20))
        persons.add(Person("michael","010-5678-1234",21))
    }
}

data class Person(
    var name:String="",
    var phone:String="",
    var age:Int=21
)

 

 

위의 코드에서, apply 위의 코드들은 모두 주석 처리하고 Log.d를 통해 resultApply의 반환값을 확인해보면 아래와 같이 Logchat에 출력되는 것을 확인 가능하다. 

2022-05-03 00:34:20.693 20137-20137/com.example.aclass D/스코프함수: resultApply=[Person(name=scott, phone=010-1234-5678, age=19), Person(name=kelly, phone=010-3456-7898, age=20), Person(name=michael, phone=010-5678-1234, age=21), Person(name=scott, phone=010-1234-5678, age=19), Person(name=kelly, phone=010-3456-7898, age=20), Person(name=michael, phone=010-5678-1234, age=21)]

apply와 also는 마지막 코드에 어떤 값이 오든지, 스코프 함수로 돌린 변수의 값을 그대로 반환한다. (run과 let은 실행한 변수와 상관없이 마지막 값이 반환됨!) 

(ex. 만약, run과 let 마지막 줄에 size를 입력하면 3개를 넣었으면 3이 리턴된다. ) 

 

 

3.with사용법 

 

with는 위젯에 접근할때 사용하는 스코프 함수이다. 

 

# 주의! binding을 사용할때 ActivityMainBinding을 사용하기에 앞서 build gradle app모듈에서 다음과 같은 코드를 추가해야한다. 

dataBinding{
        enabled=true
    }
buildFeatures{
        viewBinding true
    }

추가로, xml파일에서 <Linearlayout>을 <layout>으로 감싸서 따로 편집을 해주어야 ActivityMainBinding을 참조할 수 있게 된다. (다음 블로그의 글을 참고하였음 ->  https://jepark-diary.tistory.com/37

 

package com.example.aclass

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.aclass.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    val binding by lazy{ActivityMainBinding.inflate(layoutInflater)}

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

        with(binding){
            button.setOnClickListener {  }
            imageView.setImageLevel(50)
            textView.text="반가워"
        }

    }
}

이 코드를 작성하기에 앞서 xml파일에 button, imageview, textview 위젯을 추가해주었다. 

위 코드와 같이, 위젯에 접근하고자할때는 run 등의 방식이 아닌 with을 사용한다. 

 

 

배치를 담당하는 레이아웃 다루기

 

-ConstraintLayout (초기에 만들어져 있음) : 위젯과 레이아웃의 관계 설정(constraint) 

*RelativeLayout이 ConstraintLayout과 비슷한 기능. 구버전 느낌. 

 

Layout 구성이 가능하다. 레이아웃이 깨지는지 아닌지를 확인하고 싶을때는 왼쪽 상단 Orientation for Preview 버튼에서 Landscape 모드를 통해 깨지는지 아닌지 확인이 가능하다. 

 

서로 위젯을 연결해줌으로써 계층구조를 만들어 줄 수 있다. (위젯 하나를 이동시키면 다 따라서 이동함.) 

 

-Chains : 일정 비율로 고르게 배치 가능

 

layout_width, height를 0dp로 설정하여  화면에 꽉 채우게 배치할 수 있다.

 

 

-LinearLayout: 

*Horizontal

스택처럼 추가되어 배치됨. (horizontal)

 

*Vertical

위젯들이 세로로 누적되어 배치되는 모습 확인이 가능. 

(linearlayout은 기본적으로 scroll 기능이 없음.) 

 

-ScrollView : 스크롤 만듦 

ScrollView - LinearLayout(vertical) 

화면이 넘어가도록 위젯들을 추가해주어도 스크롤 기능을 지원하기 때문에 스크롤을 올리면 생성했던 위젯들이 모두 그대로 화면을 넘어가서도 존재 가능하게 할 수 있다. 

 

 

-FrameLayout: 레이어 겹쳐서 사용 가능 

구현된 것이 많이 없어서 빠르다. 

 

 

**

Textview 위젯의 All attributes 항목에서 위젯이 가지고 있는 모든 속성들을 변경해줄 수 있다. 

위에서는 layout_gravity 속성에서 center를 true값으로 변경시켜주었다.

이 경우, textview 위젯이 부모 레이아웃의 center로 위치하게 된다. 

 

리스너 이해하기 

 

-View - OnClickListener 

-object (for interface)

 

 

버튼 및 스트링 소스 다루기

-attribute 

-text에 값을 직접 넣는 방식 잘 사용 x (string 키워드 사용) (for 오타방지, 다국어 지원)  

 

 

'💻STUDY > ANDROID STUDY' 카테고리의 다른 글

[Android-Kotlin] 6주차  (0) 2022.05.16
[Android-Kotlin] 5주차  (0) 2022.05.09
[Android-Kotlin] 3주차  (0) 2022.04.02
[Android- Kotlin] 2주차  (0) 2022.03.27
[교양과목 복습] Eclipse - Java  (0) 2022.03.12

댓글