programmmingphil의 등록된 링크

 programmmingphil로 등록된 티스토리 포스트 수는 39건입니다.

[Jetpack Compose] Custom Dynamic theme(동적 테마) [내부링크]

-여는 글 앱을 통해 사용자에게 어떤 정보를 알려줄 때 중요한 정보를 강조하거나 참고자료를 첨부하는 것은 사용자 경험에 있어서 아주 중요하다. 왜냐하면 제작자가 전달하고자 하는 내용을 짐작하거나 이해하는데 도움 줄 수 있기 때문이다. 예를 들어 미세미세라는 미세먼지 정보 앱에서 대기오염 정도에 따라 웃는 표정 및 파란 배경을 보여주면 우리는 한눈에 공기질이 좋은 것을 알 수 있다. 이러한 이유로 데이터에 따라 동적으로 테마를 변경해야 할 때가 있다. 기존 View시스템에서는 theme resource를 적절히 조작하여 동적으로 테마를 변경할 수 있었다. 반면 Compose에서는 xml이 사용되지 않고 kotlin으로 대체되었기 때문에 작동 방법이 아주 다르다. 여러 커스텀 테마를 만들고 그것을 효율적으로..

[Room] Full-Text Search + prepopulated DB 적용기 [내부링크]

- 여는 글 어떠한 기능에서 사용자가 선택할 수 있는 데이터가 아주 많은 경우, 개발자는 사용자가 검색을 통해 선택할 데이터의 범위를 좁히고 제시할 수 있다. 이 글에서는 내가 검색기능을 앱에 적용할 때 고민하고 느꼈던 것들을 기록한다. - LIKE vs FTS 검색 기능을 생각하면 대표적으로 2가지 방법이 떠오른다. FTS를 사용하거나 LIKE 문을 이용한 검색이다. 각각의 특성을 고려해서 결정을 내려야 한다. FTS는 한국말로 전문 검색이라고 하며, 아주 많은 양의 긴 문장(ex. email, 글 내용 등)에서 특정 단어를 찾을 때 효과적으로 찾기 위해 TEXT형과 같은 색인을 둘 수 없는 컬럼에 색인을 생성하여 색인을 효율적으로 하는 기능을 말한다. Android Room의 기반이 되는 Sqlite..

Jetpack Compose 당겨서 새로고침(Pull To Refresh) + Lottie [내부링크]

- 여는 글 새로운 앱을 Compose를 이용해 개발 중인데, 밋밋한 앱에 포인트를 주면 좋을 것 같아서, 일반적인 CircleIndicator를 사용하지 않고 아래와 같이 Lottie를 이용하여 당겨서 새로고침 기능을 만들어 보았다. - 당겨서 새로고침 1) 새로고침 상태 새로고침 상태는 두가지로 나뉜다. '새로고침 중인가? 아닌가?'이다. var refreshing by remember { mutableStateOf(false) } 2) 새로고침 실행 만약 UIThread에서 새로고침을 실행하면 새로고침 되는 동안 UI가 Block 된다. 그래서 코루린스코프 위에서 새로고침을 실행하고, 예제에서는 3초 후에 새로고침이 완료되도록 했다. 실제 앱에서 새로고침으로 데이터를 가져올 땐 viewModel에서..

데이터베이스 기초 (1) [내부링크]

1. 데이터 베이스란 무엇이고 왜 사용하는가? 데이터 베이스란 구조화된 데이터들의 집합이다. 여기서 구조화되어 있다는 부분이 중요하다. 무수히 많은 데이터가 어떠한 형태나 형식 없이 랜덤한 위치에 배치된다면 데이터를 관리 및 조작하는 것이 매우 어려울 것이다. 여기서 데이터 베이스를 사용하는 이유가 나온다. 데이터베이스에서 데이터를 관리하기 위해 다양한 방식으로 데이터를 구조화된 형태로 삽입해야 한다. 그리고 데이터베이스 소프트웨어(DBMS)는 일반적으로 데이터의 쉬운 관리(유효성 검사, 보안 등) 및 조작(정렬, 삽입, 삭제 등)을 위해 여러 가지 방법을 제공한다. 이를 통해 대용량의 데이터도 논리적, 구조적으로 관리할 수 있게 된다. 일반적으로 DBMS와 저장된 데이터베이스를 통칭하여 데이터베이스라고..

자료구조 - B트리 [내부링크]

- B트리란? 색인(index)의 규모가 매우 크다면 메인 메모리가 아니라 불가피하게 디스크에서 데이터를 둬야한다. 메인메모리가 충분하지 않을 때도 마찬가지이다. 디스크에 색인을 두어야 한다면 디스크의 특성을 최대한 활용하여 디스크 접근 시간으로 인한 비효율을 최대한 줄여야 한다. 이로 인해 나온 것이 B트리이다. - B트리의 특징 1) k개의 노드가 있다면 k+1개의 자식트리를 가진다. 2) 서브 트리 Ti의 모든 키들은 key i-1보다 크고 key i보다 작다. 3) 루트를 제외한 모든 노드는 [k/2] ~ k개의 키를 갖는다. 4) 모든 리프 노드는 같은 깊이를 가진다. 5) 노드는 정렬된 상태이다. 6) 루트는 2개 이상의 자식노드를 가진다. -B트리 색인 ex) 8 색인 과정 - B트리 삽입 ..

자료구조 - 균형 검색 트리 [내부링크]

균형 검색 트리: 이진트리가 균형이 맞지 않는 경우 검색, 삽입, 삭제에 O(logn)의 시간이 드는 것이 아닌 O(n)의 시간이 소요되는 것을 방지하기 위해 트리 모양이 균형 잡히도록 작업한 트리. 1. AVL 트리 트리 내의 어떤 노드도 좌서브 트리와 우서브 트리의 높이 차가 1보다 크지 않은 상태로 유지되는 이진 검색 트리. - AVL트리의 수선(균형 잡기) 과정 서브트리의 높이차이가 1보다 커져서 균형이 깨지는 경우는 삽입, 삭제가 발생한 노드의 위 노드에서 발생할 수 도 있고, 아래 노드에서 2개 이상 발생할 수 도 있다. 이때, AVL트리는 좌회전 우회전을 이용하여 트리의 균형을 수선하게 되는데 자세한 과정은 아래와 같다. 1) 좌회전 기준노드(15)를 기준으로 좌회전한 경우이다. 좌회전 알고..

자료구조 - 힙(Heap) [내부링크]

- 우선순위 큐(Priority Queue) 우선순위를 가진 원소를 삽입할 수 있고, 우선순위가 가장 큰 원소를 빼내줄 수 있는 것을 말한다. - 힙(Heap) 우선순위 큐의 목적인 우선순위를 가진 원소를 삽입하고 삭제하는 것을 아주 효율적으로 다룰 수 있는 자료구조이다. 힙은 완전 이진 트리(Complete Binary Tree) 구조를 사용한다. 힙의 조건은 아래와 같다. 완전 이진 트리 모든 노드는 값을 갖고, 자식 노드 값보다 크거나 같다. - 힙의 특성 완전 이진 트리를 배열로 표현할 수 있다. 배열 A[] 로 표현하면 아래 그림과 같이 A[k]의 부모 노드는 A[(k-1)/2]이고 자식노드는 A[2k+1]과 A[2k+2]이다. - PriorityQueueInterface public inter..

자료구조 - 큐 [내부링크]

- 큐(Queue) FIFO(First In First Out)의 형태를 갖는 자료구조. 원소의 삽입(enqueue)은 항상 tail에서 이루어지고, 원소의 삭제(dequeue)는 항상 front에서 이루어짐. - 배열을 이용한 큐의 특징 큐의 최대크기를 예상할 수 있는 경우에는 배열이 적합하지만 크기를 예상할 수 없는 경우 더 큰 배열을 할당받아 옮기는 작업을 해야 한다. 아래 그림은 위의 그림에서 원소 삽입, 삭제를 한 번씩 수행한 배열이다. 그림에서 알 수 있듯 front와 tail이 삽입과 삭제를 거칠수록 뒤로 점점 밀린다. 그러다 보면 앞쪽의 공간이 남게 되고 공간이 비효율적으로 사용된다. 이를 해결하기 위해 배열을 원형으로 해석한다. 배열의 끝을 지나 새로운 원소(Collins)를 삽입할 때 ..

자료구조 - 스택 [내부링크]

- 스택 스택은 맨 위의 원소만 접근 가능하다. 맨 위의 원소를 TOP 원소라고 하며, 삽입(Push), 삭제(Pop) 모두 TOP에서 이루어진다. - 가상메모리에서 스택 영역 아래 그림은 가상메모리의 일반 구조다. 가상메모리에서 수행된다는 가정하에 컴파일러가 컴파일하고 물리적인 메모리에는 수행 시점에 대응된다. 데이터 부분에는 전역변수와 정적변수 등이 있다. 힙 영역에는 프로그램 수행 중 할당받는 메모리(ex.객체)가 저장된다. 스택 영역에는 함수의 파라미터와 지역변수 등 active 된 함수의 정보가 저장된다. 스택 영역이 스택 구조를 사용한다. - StackInterface public interface StackInterface { public void push(E newItem); public ..

자료구조 - 리스트 [내부링크]

- 기본 리스트 개념 설명 Node: item과 next 필드로 구성되는 객체. item 필드에 기초타입, 객체가 올 수 있고, next 필드에 다음노드를 가리키는 참조(레퍼런스)가 올 수 있다. LinkedList : 위에서 설명한 Node를 이어 붙여서 만든 리스트. 노드는 런타임시(동적으로) 공간을 할당받는다. ArrayList: 컴파일 시점에(정적으로) 일정한 공간을 할당받는다. 공간의 연속성이 있다. - LinkedList vs ArrayList 배열 리스트는 연속된 공간에 원소를 저장하지만 연결리스트는 공간의 연속성이 없다. 그래서 배열리스트가 정렬 및 검색에서 유리하고 연결리스트는 내부에 노드로 이루어져 있기 때문에 참조를 저장하기 위한 공간이 더 필요하다. 하지만 배열리스트는 들어올 원소의..

[Jetpack Compose] Custom Snackbar with Scaffold [내부링크]

Snackbar를 쉽게 커스텀하는 방법에 대해 기록한다. - 완성본 - Scaffold layout Scaffold는 자주 사용되는 Material design 컴포넌트를 쉽게 배치하고 사용할 수 있게 만들어진 layout compose이다. 위의 코드는 Scaffold의 인자들인데 snackbar를 Scaffold layout 내부에 구현하기 위해서 snackbarHost를 넘겨 주어야 한다. - SnackbarHost 커스텀하기 1) snackbar의 조작은 모두 SnackbarHost를 통해 이루어진다. 2) 필수적인 인자는 hostState뿐이다. hostState인자에 SnackbarHostState를 넘겨주어야 snackbar의 state를 snackbarHost가 알게되고 snackbar를 ..

자료구조 스터디 1주차 [내부링크]

https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=287377905 쉽게 배우는 자료구조 with 자바 기본 자료구조와 알고리즘을 밀도 있게 풀어낸 기본서다. 기본 원리는 이해하기 쉽게 단계별로 차근차근 설명하면서도 구현을 위해 논리의 골격을 구성해가는 과정에서는 저자의 내공까지 충 www.aladin.co.kr '쉽게 배우는 자료구조 with 자바' 책의 내용을 정리한다. - Chap.01 이 챕터에서는 소위 말하는 능력 있는 개발자가 되기 위해 왜 자료구조를 잘 사용하고 이해하고 있어야 하는지 독자에게 납득 시키는 챕터이다. 자료구조 그 자체로 여러 알고리즘을 포함하기 때문에 알고리즘과 자료구조는 밀접하게 관련이 있다. 추상: '관점이 계층화되어 상승한 것'...

Global Destination - Navigation Component [내부링크]

카카오톡의 전체 설정 버튼은 Bottom Navigation View의 5가지 탭에서 모두 다 접근 가능해야 한다. 이를 구현하려면 단순히 nav_graph.xml에서 각 프래그먼트에서 설정 프래그먼트로 가는 액션을 일일이 정의해줄 수 있다. 하지만 번거롭다. 그래서 Global Destination이라는 것이 있다. - 적용법 1. nav_graph.xml에서 Global Destination으로 설정할 SettingFrgment를 추가한다. 2. SettingFragment를 오른쪽 클릭 후 add Action -> Global을 선택한다. 3. 왼쪽 큰 화살표가 생긴 것을 확인할 수 있다. - 예시 class MainActivity : AppCompatActivity() { override fun ..

IdeaVim 복사, 붙여넣기 연동 [내부링크]

-문제점 Android Plugin으로 IdeaVim을 사용할때 기존 Ctrl + C / V 가 안되어서 매우 불편했다. -해결 1. Android studio 오른쪽 하단의 V 마크를 누르고 Open ~/.ideavimrc를 누른다. 2. 아래 코드를 내부에 작성하고 프로그램을 껐다 켜본다. set clipboard+=unnamed 내 코드를 안드로이드 스튜디오에서 y키로 복사하고 인터넷에서 Ctrl+V 하면 붙여넣어진다. 반대로 인터넷에서 Ctrl+C로 복사하고 p키로 안드로이드 스튜디오에 붙여넣는다.

Android Repository Pattern And Caching [내부링크]

레포지토리 패턴은 데이터 계층을 다른 나머지 앱들로 부터 완전 분리시키는 디자인 패턴을 말한다. UI 계층이 사용자에게 정보를 보여줄동안, 데이터계층은 networking, Room DB, error handling 등 데이터와 관련된 모든 작업을 한다. 레포지토리를 데이터 계층의 맨 윗단에 둠으로써 Model(persistent), Remote Data Source(retrofit, webservice)을 중앙집중화 할 수있고 데이터 간의 충돌을 최소화 할 수 있다. 위의 그림을 보면 ViewModel은 Repository에 대해서만 알고 내부의 Model 등 데이터 계층이 작동하는 방식은 알필요가 없어진다. 그래서 내부 로직의 변화로 인한 외부의 변화가 전혀 없어지고 결과적으로 서로에 대한 의존성도 ..

공유객체 스레드 동기화 (Kotlin) [내부링크]

2022.10.19 - [코틀린] - Kotlin @Volatile에 대해 Kotlin @Volatile에 대해 ServiceLocator에 대해 공부하던 중, 평소 잘 몰랐던 @Volatile 어노테이션에 관해 설명한 구글 CodeLab의 내용을 기록한다. object ServiceLocator { @Volatile var tasksRepository: TasksRepository? = null }.. programmmingphil.tistory.com 이전 @Volatile관련 글 이어서, @Volatile의 문제점이었던 동시에 읽고 쓰이는 공유 객체에서 스레드 동기화를 적절하게 사용하는 방법에 대해 기록한다. Atomic Synchronized block 스레드 한정 Mutex Actor - Ato..

Kotlin @Volatile에 대해 [내부링크]

ServiceLocator에 대해 공부하던 중, 평소 잘 몰랐던 @Volatile 어노테이션에 관해 설명한 구글 CodeLab의 내용을 기록한다. object ServiceLocator { @Volatile var tasksRepository: TasksRepository? = null } 위의 코드는 CodeLab에 나온 예제 중 일부이다. 예제에서 taskRepository변수는 여러 스레드에서 동시에 불려질 수 있기 때문에 @Volatile 어노테이션을 붙여야 한다고 적혀있다. 자세한 내용을 동작 원리에 대한 설명은 아래와 같다. Annotate INSTANCE with @Volatile. The value of a volatile variable will never be cached, and al..

Android enum class를 사용한 view의 분기 처리 [내부링크]

우리는 많은 경우 앱에 필요한 데이터를 앱 외부에서 불러온 후 view에 데이터를 바인딩한다. 이때 만약 어떠한 이유로 데이터 호출에 실패한 경우, view에는 빈 값의 데이터가 들어간다. 우리는 이것을 방지하기 위해 데이터를 불러오지 못했을 때 분기를 나누어 화면에 다른 view를 띄워준다. 예를 들어, RecyclerView에 표시할 데이터를 리스트 형식으로 받아온다고 가정 했을 때 분기를 나누어보자면, 로딩 중이라면 loading_animation을 보여준다. 로딩 실패라면 원래 나왔어야할 RecyclerView대신 "로딩 실패"라는 TextView를 띄운다. 로딩 성공이라면 RecyclerView를 보여준다. 이런 식으로 분기를 나누어 사용자에게 더 명확한 화면의 현재 상태를 보여줄 수 있게 한다..

Thread and Coroutines (Kotlin) [내부링크]

코틀린에서 멀티태스크, 병행성(concurrency)를 위해 여러가지 방법이 있다. 여러 방법 중 기본적인 스레드와 스레드의 문제점을 개선한 코루틴을 비교해보려한다. - 스레드 스레드는 멀티태스크를 위한 가장 기본 방식이다. 하지만 스레드의 생성, 전환, 관리시에 시스템 자원을 크게 소모한다. 또한 프로세스의 특성으로 인해 다루기 어렵고 예측 불가능 하다. 앱 개발에서 mainThread가 UI 생성 및 관리를 맡고 있는데, 요즘은 휴대폰에서 120Hz를 지원한다. 그러면 초당 60~120번의 UI생성이 이루어 지는 것이고, mainThread는 이것을 한 프레임당 16ms 보다 짧은 시간에 해야한다. 물론 프레임 드랍이 생기는 것은 흔하지만 자주 발생한다면 앱 사용성을 해치고, 최악엔 앱에서 충돌이 일..

Android onBackPressedCallback in Fragment [내부링크]

Activity는 사용자가 Back버튼을 물리적, 소프트웨어적으로 작동시켰을 때 androidx.activity.ComponentActivity의 onBackPressed() 함수를 사용하여 내가 원하는 동작을 하게 할 수 있다. 하지만 Fragment의 경우 직접적으로 onBackPressed()함수를 호출 할 수 없기 때문에 onBackPressedDispatcher라는 것을 사용해서 callback을 직접 등록해야 한다. - onBackPressedDispatcher Back 버튼의 이벤트가 하나 혹은 여러개의 onBackPressedCallback에 전달되는 것을 제어하는 역할을 한다. 여기에 addCallback()메서드를 사용해 콜백을 전달한다. 이때 addCallback메서드의 매개변수로 L..

const val 과 val 차이점 (Kotlin) [내부링크]

- 공통점 const val과 val 둘 다 read only - 차이점 1. const val로 선언 할 경우 원시타입, String으로만 초기화 가능하다. 반면 val은 함수 및 객체 등 여러가지 타입으로 초기화 가능하다 2. const val은 컴파일 시점에 인라인으로 참조가 실제값이 되고 , val은 런타임에 생성된다. 3. const val은 파일 최상단 혹은 클래스의 companion object에 선언해야한다. 4. 불변성은 같지만 val 같은 경우 초기화의 특성에 따라 값이 달라지는 경우가 있다. - 예시 private val _quantity = MutableLiveData() val quantity: LiveData = _quantity _quantity는 MutableLiveData로..

SimpleDateFormat 사용법 [내부링크]

날짜를 표시하기 위해 SimpleDateFormat을 사용했는데 착각한 내용과 여러 가지 사용법을 기록한다. - 사용법 SimpleDateFormat은 첫번째 매개변수로 시간 패턴을 넣어주고, 두 번째 매개변수로 Locale을 넣어줄 수 있다. 이때 나는 Locale과 TimeZone을 혼동했다. Locale은 시간대 설정이 아니라 지역 설정이다. 그래서 아래와 같이 E요일에서 일요일이 나오는 것이다. val formatter = SimpleDateFormat("yyyy-MM-dd E HH:mm:ss", Locale.US) val formatter1 = SimpleDateFormat("yyyy년 MM월 dd일 E요일 HH:mm:ss", Locale.KOREA) formatter.format(System...

Android Testing LiveData [내부링크]

구글 CodeLab에서 읽은 LiveData를 테스트하기 위한 좋은 방법을 기록한다. LiveData를 테스트하기 위해 2가지 일을 해야한다. 1. Use InstantTaskExecutorRule 2. Ensure LiveData observation - InstantTaskExecutorRule 이것은 JUnit에서 정의한 규칙이다. 클래스에 @get: Rule 어노테이션을 통해 이 규칙을 정의하면 해당 클래스에서 발생하는 모든 아키텍처 컴포넌트(LiveData)의 백그라운드 실행을 하나의 스레드에서 작동시켜준다. 그로 인해 thread safe 한 상태에서 테스트를 동작시킬 수 있다. InstantExecutorRule()이 정의된 라이브러리를 사용해야 한다. testImplementation "a..

MPAndroidChart 가로 꺾은선 그래프 [내부링크]

WITHUB 어플을 제작할 때 사용자의 한 달 깃허브 커밋 횟수를 가로 꺾은선 그래프로 나타내야 했다. - 초기 설정 //app 수준에 추가 implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' //settings.gradle에 추가 maven { url 'https://jitpack.io' } - activity_main.xml ScrollView의 내부는 LinearLayout으로 감싸주어야 한다. 또 LineChart 뷰의 넓이는 넣는 값의 범위에 따라 적당히 크게 입력한다. - 데이터 셋 생성 data class CommitData(val date: String, val commitNum: Int) val dataList: List = listOf..

TDD By Example(Kent Beck) with Kotlin(1부) [내부링크]

테스트 주도 개발의 기초를 다지기 위해 켄트 백이 쓴 책 TDD By Example 속 인상적이었던 몇 가지 예제를 코틀린으로 따라 하고 정리한다. 내가 정리하고 싶은 부분만 느낀 점 위주로 정리한 글이다. 전체 예제는 책을 사서 보거나 깃허브의 내가 작성한 예제 코드를 보길 바란다. http://www.kyobobook.co.kr/product/detailViewKor.laf?barcode=9788966261024 테스트 주도 개발 - 교보문고 Test-Driven Development: By Example아름다운 코드와 즐거운 개발을 위한 테스트 주도 개발테스트 주도 개발은 학계와 업계에서 많은 주목을 받아온 프로그래밍 방법으로, 여러 연구 논문과 실례를 통해 www.kyobobook.co.kr ht..

안드로이드 스튜디오 콘솔 한글깨짐 [내부링크]

-문제 JUnit5의 @DisplayName 기능을 사용할 때, 한글이 깨지는 경우가 발생했다. -해결 Help - EditCustom Vm Options에 아래 두 문장 추가. -Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8

안드로이드 스튜디오 JUnit5, Instrumental Test 초기 설정 [내부링크]

JUnit4에서 JUnit5로 버전을 이동할 때 추가해야 할 것들을 기록한다. 1. 기본 요구사항 Use Android Gradle Plugin 3.5.0 or higher Use Gradle 6.1.1 or higher Use Java 8 2. Project 수준 build.gradle에 플러그인 다운로드 //이거 추가 buildscript { dependencies { classpath("de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1") } } plugins { id 'com.android.application' version '7.2.1' apply false id 'com.android.library' version '7.2.1' apply fal..

SOLID 원칙 [내부링크]

중간 규모의 모듈에서 (함수 하나, 클래스 하나는 작은 모듈) 읽고 쓰기 쉬운 코드를 위해 더 나아가 협업 및 유지 보수에 유리하고, 여러 소프트웨어 시스템에 사용 가능한 코드를 작성하기 위해 설계에서 지키면 좋은 5가지의 원칙이다. 1. Single Responsibility (단일 책임 원칙) 하나의 모듈은 하나의 액터 특성만을 가져야 한다. 액터란 말의 의미는 아래 예시를 보면 이해된다. class Menu { fun getMenuFromServer(){...} fun showMenu() {...} fun alerterAllergicInfo(){...} } 위의 코드는 단일 책임 원칙에 어긋난 설계이다. 그 이유로 메뉴라는 클래스는 메뉴 그자체에 관한 특성 만을 가지고 있어야 한다. 예를 들면 메뉴..

리사이클러뷰 어댑터 setOnClickListener [내부링크]

-기존 코드 inner class FriendRepoListHolder(val binding: RecyclerViewItemFriendRepoListBinding) : RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FriendRepoListHolder { val binding = RecyclerViewItemFriendRepoListBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return FriendRepoListHolder(binding) } override fun onBindView..

ViewModel 생성시 매개변수 전달방법 [내부링크]

WITHUB 앱을 만들던 중 val friendNickName = intent.getStringExtra("friendNickName") 위와 같이 액티비티에서 string을 받아서 ViewModel의 생성자로 넘겨주어야 하는 상황이 있었다. 기존의 ViewModel 생성시에는 val friendViewModel: FriendViewModel by viewModels() 이렇게 만들었지만, 생성자가 있는 경우 ViewModelFactory를 직접 커스텀하는 과정이 필요하다는 것을 구글링을 통해 알게 되었다. class FriendViewModelFactory(private val friendName: String?) : ViewModelProvider.NewInstanceFactory() { overri..

Android oss-licenses 적용(Licenses are only provided in build variants 문제) [내부링크]

-문제점 WITHUB 어플에서 사용한 라이브러리가 상당히 많았다. 일일이 오픈소스 라이선스를 찾아 레이아웃에 넣을 생각 하니 눈앞이 깜깜했다. -해결 구글플레이스토어에서 oss-licenses라는 좋은 라이브러리를 만들어놔서 아주 쉽게 라이선스를 앱에 등록할 수 있다. //project 수준 buildscript { repositories { ... google() } dependencies { ... classpath("com.google.android.gms:oss-licenses-plugin:0.10.5") } } //app 수준 plugins { ... id("com.google.android.gms.oss-licenses-plugin") } dependencies { ... implementat..

Do not concatenate text displayed with setText.(Format Specifiers) [내부링크]

-원인 코드에 text자체를 적었을 때 발생하는 경고이다. values/strings 안에 text를 정의해야 유지 보수가 유리하다. text = "${item.owner}/${item.name}" //경고 / 때문에 -해결 포맷 지정자(Format Specifiers) %[parameter_index$][format_type] %: 포맷지정자 시작을 알림 parameter_index: 파라미터 번호, 뒤에 $ 붙여야함 format_type: s - String, d - 정수, f - 실수 //values/strings 안에 선언 %1$s/%2$s context.getString(R.string.repo_item_format, item.owner, item.name) //결과 "owner/name" -참..

안드로이드 DiffUtil (Databinding에서 중요한이유) [내부링크]

DiffUtill은 두 개의 리스트를 서로 비교하여 다른 요소만 바꾸어주는 유틸리티 클래스이다. 공식문서에 따르면 이 알고리즘은 O(N)의 공간과 O(N + D^2)의 성능을 가진다. Databinding에서 DiffUtil이 아주 중요하다고 생각하는 이유는 DataBinding을 통해 RecyclerView를 구현할 때 리사이클러 어댑터에 전달되는 items가 있다고 하자. 이 items은notifyDataSetChanged(), notifyItemChaged(position:Int) 등등 개발자가 직접 분기를 나누어 줘야 했다. 만약 단순히 Item하나만 추가되는 상황에서 notifyDataSetChaged()를 호출하는 것은 아주 비효율적이기 때문이다. 내가 겪었던 문제를 설명하자면, viewMod..

Delegated properties(Kotlin) [내부링크]

2022.08.19 - [코틀린] - Kotlin 'by' (Delegation_Kotlin) Kotlin 'by' (Delegation_Kotlin) 코틀린으로 개발을 하다 보면 'by'를 자주 쓰게 된다. 간단한 예제를 통해 by가 어떤 의미로 코틀린에서 쓰이는지 기록해본다. -예시 interface Home { fun sleep() } class HomeImpl(val owner: String) : Home.. programmmingphil.tistory.com -Delegation property Property의 접근자 로직(ex get, set 등)을 다른 객체에 위임하는 것이다. -예시 적용 전 class Home(private val _tv: String, private val _roomN..

Kotlin 'by' (Delegation_Kotlin) [내부링크]

코틀린으로 개발을 하다 보면 'by'를 자주 쓰게 된다. 간단한 예제를 통해 by가 어떤 의미로 코틀린에서 쓰이는지 기록해본다. -예시 interface Home { fun sleep() } class HomeImpl(val owner: String) : Home { override fun sleep() { println("$owner 집에서 잔다") } } class Derived(home: Home) : Home by home fun main() { val home = HomeImpl("원해성") Derived(home).sleep() } // 결과 : 원해성 집에서 잔다 위 예시에서 Derived클래스는 Home Interface를 구현하려고 하는데 구현을 매개변수로 받는 home에게 맡긴다(위임한..

AndroidViewModel vs ViewModel [내부링크]

ViewModel을 생성할 때 AVM과 VM 중에서 어떤 것을 골라야 할지 고민을 했다. -기준 1. ViewModel 내부에서 Context가 필요하다면 AVM을 사용한다. 그 외에는 VM > AVM내부에서는 getApplicationContext()를 통해 ApplicationContext를 얻을 수 있다. 2. AVM은 UnitTest와 맞지 않는다. > UnitTest는 Android생명주기와 관계없이 독립적으로 실행되어야 하기 때문이다.

안드로이드 Context에 관하여 [내부링크]

-공식문서 Context 정의 Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc. 직독 하자면 애플리케이션 환경에 관련된 전역 정보를 나타내는 인터페이스이다. 안드..

안드로이드 패키지구조 [내부링크]

WITHUB 앱을 설계할 때 패키지 구조에 대해 고민을 했었다. 초기에 무작정 2명이서 개발하니 각각 배정한 파트(로그인 부분과 메인 부분)로 구분했고, 그 안에서 Activity는 Activity끼리, Fragment는 Fragment끼리 폴더를 만들었다. 결과적으로 아주 가독성 떨어지고 혼잡한 패키지 구조가 되었다. -기존 패키지 구조 이걸 구조라 하기도 민망할 정도로 레이어 별로 쌓아 놓았다. 심지어 앱 공통으로 사용되는 network, model부분도 함께 나열 되어있어 더 난잡한 느낌이다. -수정된 패키지 구조 아키텍처를 MVVM으로 전환 앱의 규모가 커져감에 기능(도메인)별로 패키지를 정리했다. 우선 최상단 패키지로 data와 feature로 구분했다. data패키지 내부에는 model, ne..

Android JUnit5 local test Context 문제 [내부링크]

- 문제점 JUnit5 local test에서 applicationContext를 얻는 방법이 없다. -원인 Why make the view model test a local test? Pure view model tests usually go in the test source set because the view mode..