본문 바로가기

전체 글

(13)
[Day 1] Kotlin에서 val은 상수인가? 코틀린으로 개발할 때 가장 먼저 배우는 것은 var vs val 이 아닐까 싶다. 모두 알다싶이 var 은 새 값을 할당할 수 있지만, val 은 재할당이 불가능하다. 특히 코틀린으로 개발할 때 "가변 변수인 var 대신 불변 변수인 val 을 사용하라"는 규칙을 많이 접하게 되는데, 그렇다면 "Kotlin의 val은 불변(Immutable)을 보장하나요?"라는 질문을 받으면 어떻게 답할 수 있을까?1. 한 줄 요약val은 참조의 재할당만 막는 읽기 전용(read-only) 프로퍼티일 뿐, 커스텀 getter나 가변 객체 참조를 통해 호출 시마다 다른 값을 반환할 수 있으므로 불변(immutable)을 보장하지 않는다. 진짜 컴파일 타임 상수를 만드려면 const val을 사용해야한다.2...
[Day 0] 100일 동안 안드로이드 파보기 100일 동안 안드로이드 파보기?코드를 작성할 때 AI를 사용하는 것이 일상이 되었고, 심지어는 요구사항을 입력조차 할 필요 없이 링크만 복사-붙여넣기해도 그럴듯하게 동작하는 코드가 뚝딱 나온다. 당장의 기능을 구현하고 티켓을 쳐내는 속도는 확실히 빨라졌지만, 이대로라면 나를 "개발자"라고 부를 수 있을까? 라는 의문이 든다.특히 최근 두어군데의 기술 면접을 진행했는데 조금만 근원적인 질문이 나와도 쉽게 답이 나오지 않았다. AI로 동작하는 코드는 만들 수 있어도, 그걸 알고 이해하지는 못한 것이다.이런 상황을 타파하기 위해 100개의 안드로이드 기술 블로그 글 작성하기를 시작하려고 한다. Kotlin 코어적인 글로 시작해서 아키텍처, Compose, 성능 최적화까지 이 곳에서 Android를 내 지식으..
SavedInstanceState와 ViewModel SavedInstanceState 앱을 만들면서 늘 지나치던 아이가 있다…. onCreate에서 인자로 들어오는 savedInstanceState인데, Bundle 자료형으로 들어온다고 한다. 보통 화면을 회전할 때 사용한다고 개념적으로 알고만 있는데 이번에 직접 사용해보려고 한다. class MainActivity : AppCompatActivity() { private val binding: ActivityMainBinding by lazy { DataBindingUtil.setContentView(this, R.layout.activity_main) } var count = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(..
lifecycleOwner와 viewLifecycleOwner의 차이 Fragment에서 LiveData를 observe할 때 LifecycleOwner로 Fragment 자체를 넣게 되면 viewLifecycleOwner를 사용하라는 에러가 표시된다. 처음엔 Fragment는 lifecycleOwner가 따로 없어서 viewLifecycleOwner를 사용해야하는구나 하고 넘어갔다. 당연한 건 없었다…. Fragment는 분명 LifecycleOwner를 상속받고 있기 때문에 LiveData의 observe에서도 사용이 가능한 게 정상이다. 심지어 DataBinding의 lifecycleOwner에는 정상적으로 잘 들어가지만 observe에서 사용할 때만 빨간줄로 에러가 표시된다. 그 이유는 Fragment의 lifecycleOwner와 viewLifecycleOwner..
RoomDB에서 LiveData 사용 예전 포스팅에서 Realm이 RoomDB보다 사용이 간편해 Realm을 사용한다고 했는데, 그 중 가장 크게 작용했던 RoomDB의 단점이 Main Thread에서는 사용이 불가능하다는 점이었다. 이전 포스트 👉 Room DB 사용하기 그런데 회사 프로젝트 진행을 하던 중 LiveData를 사용하면 메인 스레드에서도 데이터를 읽어올 수 있다는 글을 보게 되었다. LiveData 자체가 비동기적으로 동작하기 때문에 Main Thread에서도 에러가 발생하지 않는다는 것이 핵심이었다. 이를 토대로 위 포스트의 코드를 리팩토링 해본다면 @Dao interface RecipeDao { ... @Query("SELECT * FROM recipe") fun getAll(): LiveData ... } 위처럼 SEL..
Android Custom View 만들기 해당 뷰 하단의 버튼들을 보면 모두 같은 레이아웃에 아이콘과 텍스트만 다르다는 것을 볼 수 있다. 이럴 때는 커스텀뷰를 사용해 뷰를 정의하면 버튼마다 레이아웃과 뷰를 만들어줄 필요 없이 커스텀 뷰 하나만 만들어주면 되기 때문에 상당히 편리하다. 커스텀뷰를 만드는 것은 세 단계를 거친다. 뷰 구현 속성 정의 뷰 클래스 구현 1. 뷰 구현 우선 커스텀뷰의 xml 파일을 만들어준다. 데이터바인딩을 사용하기 위해 layout 태그로 감싸는 것도 잊지 말자. 대략 원하는 형태의 뷰가 만들어졌다. 2. 속성 정의 이제 해당 뷰에서 사용하는 속성을 정의해야한다. 해당 뷰에서는 이모지, 타이틀, 카운트가 다르므로 세 개의 속성을 받을 것이다. values 폴더 내에 attrs.xml 파일을 만들고 속성과 자료형을 입력..
RxSwift Input/Output 구조 사용하기 RxSwift와 MVVM을 프로젝트에 적용시키기 위해 다양한 글들을 읽어봤는데 가장 보편적으로 사용되는 패턴이 Input/Output 패턴인 것 같았다. 해당 패턴은 두 가지 방법으로 구현이 가능했는데 첫 번째는 ViewModel 내에서 Input, Output 객체를 생성하고 View에서 바인딩하는 방법 두 번째는 View에서 Input 객체를 생성하고 ViewModel의 transform의 함수를 호출해 Output 객체를 반환받아 사용하는 방법이 있었다. 개인적으로 View에서는 ViewModel의 데이터에 직접 접근해 수정이 가능하도록 만드는 것이 MVVM과는 살짝 거리가 있다고 생각해서 두 번째 방식을 선택했고 코드는 아래와 같다. // ViewModel.swift protocol ViewMod..
Array의 toList()와 asList() Array를 List로 변환하는 중에 Array의 메서드로 toList()와 asList()가 있는 것을 보고 무슨 차이점이 있는 건지 궁금해 검색해봤다. 1. toList() toList()는 대상 Array를 복사해 새로운 인스턴스로 반환한다. val array = arrayOf(1, 2, 3) val list = array.toList() array[0] = 4 println(list) // 1, 2, 3 2. asList() asList()는 대상 Array와 동일한 배열 요소를 공유하는 List를 반환한다. val array = arrayOf(1, 2, 3) val list = array.asList() array[0] = 4 println(list) // 4, 2, 3 toList()와 달리 ..