Section 04
🎲 DataBinding (데이터바인딩)
기존의 방법
val btn = findViewById<Button>(R.id.testbtn)
btn.setOnClickListener { ... }
- findViewById()로 뷰를 찾아서 코드에서 데이터를 넣어줌.
- 단점:
- 코드가 길어짐
- 매번 뷰를 찾아야 함
- UI와 데이터가 따로 놂 → 유지 보수 어려움
Data Binding
- UI 레이아웃과 데이터(코드)를 직접 연결해주는 라이브러리/기능
- *장점: *
- findViewById 필요 없음 → 뷰를 자동으로 바인딩
- UI와 데이터 연결 직관적 → XML에서 데이터 참조 가능
- 양방향 바인딩 가능 → UI 값이 바뀌면 데이터도 바뀌고, 반대도 가능
- MVVM 아키텍처와 잘 맞음
MVVM(Model–View–ViewModel)
안드로이드 앱 아키텍처 패턴 중 하나로, 앱을 역할별로 분리해서 유지보수와 확장성을 쉽게 만드는 구조
Data Binding 쓰는 법
[build.gradle.kts] : android 코드 블럭 안에 dataBinding true 추가하기
buildFeatures {
dataBinding = true
}[activity_main.xml] : 기존의 레이아웃을 <layout></layout> 블록으로 감싸기
[MainActivity.kt] : binding 방식으로 버튼과 코드를 바로 연결. 즉, findViewById로 버튼을 찾을 필요가 X
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)
}
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// Databinding 방식
binding.testbtn.setOnClickListener{
Toast.makeText(this, "2번 방식 click", Toast.LENGTH_LONG).show()
}
}
}
🎲 변수 & Log
[val] vs [var]
1. val
- 불변(immutable) 변수, 값의 읽기만 허용하는 변수 (자바에서 final과 유사)
- Value의 약자
- 초기에 값을 할당하면 나중에 값을 변경할 수 없음
- 강제로 변경하려고 하면 → 컴파일 에러
- But, 변수의 참조가 가리키는 객체 내부 값은 변경이 가능
// 1. 기본 할당
val name = "Tave"
// name = "kotlin" // 이런식으로 변경하려면 컴파일 에러 발생
// 2. 타입 지정 가능, 초기화 시 값을 할당하지 않을거면 반드시 타입을 지정해야 함
val name: String
name = "Tave"
// 3. 코드 문맥에 따라 val 변수가 1번만 초기화 된다면 여러값 할당가능
val name: String
if(...){
name = "java"
} else {
name = "kotlin"
}
// 4. 변수의 참조가 가리키는 객체 내부 값은 변경이 가능
val arr = arrayListOf("kotlin")
arr.add("java") // 가능! -> arr 참조는 바뀌지 않지만 내부 객체는 변경 가능하기 때문
2. var
가변(mutable) 변수, 값 변경이 가능
Variable의 약자
처음 초기화 이후 값을 변경할 수 있지만 다른 타입의 값을 넣을 수는 X
ex) 처음에 String 타입으로 초기화 한 뒤 Int 타입의 값을 넣을 수 없음
→ 억지로 해당 변수의 뒤에서 Int 타입으로 재정의 한다고 해도 Type Mismatch Error가 발생
// 1. 기본 할당 & 수정
var age = 22
age = 23 // OK
// 2. 타입 미스매치 에러 발생
var name = "Tave"
name = 22 // 컴파일 에러: Type mismatch
// 3. 넓은 타입으로 선언하면 다른 타입도 할당 가능
var x: Any = "Tave"
x = 22 // OK
3. 추가 개념
const val- 컴파일 시간에 결정되는 상수
- 오직 문자열이나 기본 자료형으로 할당되어야 함
- 지역변수나 클래스 내부에서 할당할 수 없음
lateinit var- 늦은 초기화를 허용하는 var
- var에만 가능, val는 불가능
lateinit var name: String // token 초기화 전 접근하면 UninitializedPropertyAccessException 발생
name= "Tave"
- 컬렉션에서 불변인 경우
listOf(...): 읽기 전용 인터페이스를 제공mutableListOf(...)/arrayListOf(...): 수정 가능한 컬렉션
val immutable = listOf(1, 2, 3) // 읽기 전용
val mutable = mutableListOf(1, 2, 3) // 값 추가/삭제 가능
따라서 다음의 코드는 오류가 남
val arr = listOf("kotlin")
arr.add("java") // 오류 발생 -> 읽기 전용이어서
Log
1. Log 개념
- 앱 실행 중에 디버깅 및 상태 확인을 위해 사용되는 안드로이드 Log 클래스
- 출력되는 로그는
Logcat창에서 실시간으로 확인 가능 - 로그는 개발자가 읽는 용도. 민감한 정보를 남기는 용도 X
2. Log 종류
Log.v(TAG, msg)— Verbose: 가장 상세한 정보 (개발 중 아주 세부적인 추적용)Log.d(TAG, msg)— Debug: 디버깅용(개발 단계에서 자주 사용)Log.i(TAG, msg)— Info: 앱의 일반적인 동작/상태 알림(운영에서도 참고할 만한 정보)Log.w(TAG, msg)— Warn: 경고(문제가 될 수 있지만 앱은 계속 작동)Log.e(TAG, msg)— Error: 오류, 예외(심각한 문제 — 스택 트레이스 출력)Log.wtf(TAG, msg)— What a Terrible Failure: (대개 절대 발생하지 않아야 할 상태) — 주의해서 사용
Log.v("MainActivity", "상세 로그")
Log.d("MainActivity", "디버그용")
Log.i("MainActivity", "정보 메시지")
Log.w("MainActivity", "경고 발생")
Log.e("MainActivity", "오류 발생")
3. 사용 방법
private val TAG = MainActivity::class.java.simpleName
// 이런 식으로 클래스명(simpleName)를 태그로 쓰는 것이 일반적
Log.d(TAG, "log 찍기")
try {
// 예외가 날 수 있는 코드
} catch (e: Exception) {
Log.e(TAG, "처리 실패", e) // 예외 스택트레이스 함께 출력
}
4. 주의 사항/실무
- TAG 규칙: 클래스로 태그 통일(
MyActivity::class.java.simpleName) → 검색 쉽도록 - 레벨 적절히 사용: 너무 많은
Info/Warn/Error는 Noise가 됨 - 민감 데이터 금지: 사용자 데이터, 토큰, 비밀번호 절대 로그에 남기지 X
- 예외는 메시지 + throwable로 기록:
Log.e(TAG, "Failed to ...", ex)

🎲 앱 만들기
1. xml 레이아웃 구성

- 가장 상단에 TextView 배치 (안내 문구 표시 → 엔믹스의 'dice' 가사 인용ㅠㅋ🤣)
- 그 밑에 주사위 이미지를 보여줄 ImageView를 2개를 배치
android:layout_weight="1"→ 각 ImageView에 동일한 가중치를 주어 두 이미지가 화면에서 똑같은 비율로 나뉘어 배치되도록 설정
- 하단에 Button 배치 (button 이름은 'diceStartBtn')
2. 랜덤값 확인

Log.d("MainActivity, Random.nextInt(1,7).toString())
- 1 이상 7 미만의 정수 중 하나를 무작위로 반환
인생 고고!버튼을 누를 때 마다 MainActivity 로그에 랜덤값이 찍히는 것을 알 수 있음
3. if 조건문으로 랜덤값에 따라 주사위 이미지 출력
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val diceImage1 = binding.dice1
val diceImage2 = binding.dice2
binding.diceStartBtn.setOnClickListener {
val number1 = Random.nextInt(1,6)
val number2 = Random.nextInt(1,6)
if(number1 == 1){
diceImage1.setImageResource(R.drawable.dice_1)
} else if(number1 == 2){
diceImage1.setImageResource(R.drawable.dice_2)
} else if(number1 == 3){
diceImage1.setImageResource(R.drawable.dice_3)
} else if(number1 == 4){
diceImage1.setImageResource(R.drawable.dice_4)
} else if(number1 == 5){
diceImage1.setImageResource(R.drawable.dice_5)
} else if(number1 == 6){
diceImage1.setImageResource(R.drawable.dice_6)
}
if(number == 2) { ... }
else if(number == ...)
}
diceImage1,diceImage2변수에 각각 이미지뷰 바인딩을 참조diceStartBtn이 눌리면 두 변수에 각각 랜덤값이 할당- 랜덤값에 따라 1부터 6까지의 주사위 이미지 리소스를 ImageView에 설정해여 표시
🎲 실행화면

[👾Github] TAVE 스터디 3주차 깃허브
'TAVE-16th' 카테고리의 다른 글
| [TAVE 스터디 5주차] 메모 앱 만들기 (0) | 2026.01.04 |
|---|---|
| [TAVE 스터디 4주차] 음악 목록 앱 만들기 (0) | 2026.01.04 |
| [TAVE 스터디 4주차] ListView 만들기 & 더블클릭 종료 (0) | 2026.01.04 |
| [TAVE 스터디 2주차] 사진앱 만들기(2) (0) | 2026.01.04 |
| [TAVE 스터디 1주차] 사진앱 만들기(1) (0) | 2026.01.04 |
