프로그래밍/Android 131

[안드로이드] 실시간 네크워크 상태 callbackFlow를 이용해 만들어보자! (Youtube 인터넷 연결처럼 구현)

Youtube를 보다가 네트워크가 끊겨버렸을때 앱은 이를 알아차리고 "네트워크 연결이 불안정합니다" 같은 텍스트가 보여진다. 그러다 네트워크가 연결이되면 별 액션을 취하지 않아도 영상 목록이 뜨게된다. 계속 polling을 하는건가? 싶었지만 찾아보니 그렇게 하지 않아도 되었다. 바로 NetworkCallback을 이용하면 쉽게 구현할 수 있는데, 이 글에서는 Kotlin CallbackFlow를 이용하여 Flow로 만들어서 사용해보려고 한다. NetworkStatusTracker 우리가 만들 NetworkStatusTracker는 다음과 같은 기능을 가진다. 네트워크가 연결되면 이벤트를 방출한다. 네트워크가 끊어지면 이벤트를 방출한다. 먼저, 네트워크 연결 상태를 정의해준다. sealed class N..

[Android] 멋진 오픈소스 프로젝트 모음 - Awesome Android Kotlin Apps

https://github.com/androiddevnotes/awesome-android-kotlin-apps GitHub - androiddevnotes/awesome-android-kotlin-apps: 👓 A curated list of awesome android kotlin apps by open-source contribu 👓 A curated list of awesome android kotlin apps by open-source contributors. - GitHub - androiddevnotes/awesome-android-kotlin-apps: 👓 A curated list of awesome android kotlin apps by open-source c... github.c..

[Bitrise Cli] 리눅스 서버에서 CI/CD pipeline 직접 구축해보기 (2)

CI/CD pipeline 직접 구축해보기 (1편) https://jizard.tistory.com/405 CI/CD pipeline 직접 구축해보기 (2편, 현재 포스트) https://jizard.tistory.com/410 지난 포스팅에서는 linux 서버에 Bitrise Cli를 설치하고 구동하는 과정을 완성했다. 하지만 "Continuos"가 빠졌다. 지속적 배포를 위해서는 주기적으로 자동으로 돌아가거나 코드를 푸쉬할때 수행되는 장치가 필요하다. 그래서 Node.js Express를 이용해 Github Webhook을 받을 수 있는 웹 서버를 구축해볼 것이다. 앞선 Bitrise 과정도 Docker로 시작할걸...이라는 후회와함께 일단 Docker로 node.js를 구동할 준비를 한다. 전체 프..

[Bitrise Cli] 리눅스 서버에서 CI/CD pipeline 직접 구축해보기 (1)

CI/CD pipeline 직접 구축해보기 (1편, 현재 포스트) https://jizard.tistory.com/405 CI/CD pipeline 직접 구축해보기 (2편) https://jizard.tistory.com/410 CI/CD가 왜 필요할까? 일하다보면 빌드 시간이 너무 길게 느껴진다. QA할 버전좀 올려주세요~ 개발서버버전 올려주세요~ 그와 동시에 배포도하고... 프로가드를 사용중인 프로젝트에서 내 컴퓨터로 빌드를하면 10분정도가 걸릴때도 있었다. 무엇보다 개발 열심히 하고있는데 흐름이 끊기는게 가장 큰 문제점이다. CI/CD는 마치 UI/UX처럼 뜻은 다르지만 따라다니는 친구들인데, 앱 개발부터 배포까지 자동화하는 방법이다. CI는 지속적 통합(Continuos Integration)로,..

[Android] 진짜 쉬운 Main Thread와 Handler

Main Thread (UI Thread) 안드로이드는 UI를 업데이트하는데는 메인 스레드만 사용하는, 싱글 스레드 모델이 적용된다. 따라서 I/O나 복잡한 연산이 있는 경우 다른 스레드에서 작업하는 것이 권장된다. 멀티 스레드로 UI를 업데이트 할 경우 일반적인 멀티 스레드 문제에도 직면하게 되는데 Deadlock이나 Race condition등이 대표적인 예시이고, 이는 모든상황에도 그렇지만 특히나 UI에서 발생하면 안되는 문제이다. TextView의 글자를 업데이트 하는데, 여러 스레드에서 동시에 텍스트뷰에 접근해 값을 바꾸는 경우, 어느 한 값은 결국 버려질 수 밖에없다. 따라서 다른 스레드에서 UI를 업데이트 하려고 할 경우 Handler를 이용해 다음 작업때 “이렇게 업데이트 해주세요!”라고 ..

[Android] IllegalStateException: Method addObserver must be called on the main thread

문제발생 IllegalStateException: Method addObserver must be called on the main thread ViewModel을 가지고 뭔가 하려했을때 해당 오류가 발생하는 경우가 있다. 이것은 ViewModel을 lazy init해서 사용할 시에 발생하게 되는데, 나의 경우에는 아래와 같은 코드에서 발생했다. private val splashViewModel by viewModels() override fun onStart() { super.onStart() lifecycleScope.launch(Dispatchers.IO) { splashViewModel.doSomething() } } 원인 처음에는 "무슨 소리야 옵저버같은거 안붙였는데"라고 반발이 올라왔지만, 컴..

Bitrise에서 버전명(혹은 버전코드) 환경변수로 사용하기

Bitrise로 CI/CD를 구축하려하면 심심찮게 환경변수들을 만들고, 저장해야하는데, 사실상 변수만드는 법만 익히면 나머지는 알아서 줄줄 풀린다. Bitrise에서 정말 많은 환경변수들이 미리 정의되어있지만, 버전명이나 버전코드에 대한 환경변수는 설정되어있지 않다. 그래서 간단하게 버전명을 환경변수로 저장하는 방법에 대해서 적어보려한다. task("printVersionName") { println(android.defaultConfig.versionName) } build.gradle/app에 다음과 같이 사용자 정의 task를 추가한다. ./gradlew printVersionName -q 제대로 설정했자면 터미널에서 task를 실행하면 버전명이 그대로 찍힐 것이다. 여기서 -q는 quiet을 뜻하..

[안드로이드] Airbnb Epoxy 라이브러리 놓치기 쉬운 부분들

개발중인 앱에서 RecyclerView는 Epoxy를 사용하고 있는데 상당히 편리함을 누렸지만 제대로 알지못하고 있는거 같아서 공식문서를 쭉 훑어보았다. 이번 글에서는 공식 문서와 소개 페이지에서 설명하고 있는 요소들 중에서 놓치기 쉬웠던 부분들 몇가지를 체크하려한다. EpoxyAttribute EpoxyAttribute를 사용하면 자동 Diffing에 사용되는 hashCode()나 equals() 같은 메소드가 생성되는데, 이를 원하지 않는다면 @EpoxyAttribute(hash=false) 로 꺼둘 수 있다. 클릭 리스너처럼 매번 bind 될때마다 재생성되는 필드들에 적용하면 좋다. Hiding Models View가 조건부로 보여지고 숨겨져야할때 사용할 수 있다. model.show(boolean..

Upstream Flow, Downstream Flow

Upstream Flow Producer Block에서 생성한 Flow , 현재 연산자 전. Flow를 설명할때 대부분은 UI를 가장 아래쪽에, Remote data source를 가장 위쪽에 위치하는 도식으로 표현되는데, 상류의 물(데이터)이 아래쪽으로 내려오는식으로 이해하면된다. Downstream Flow 현재 연산자 이후의 모든 Flow collect 새로운 값이 생길때마다 호출되는 함수를 매개변수로 받는다. collect를 호출할 때마다 새 Flow가 생성된다. 이러한 Flow는 Cold Flow라고 하는데, 필요에따라 생성되고, 관찰되는 중에만 데이터를 전송하기 때문이다. StateFlow 컬렉터가 없더라도 데이터를 보관하고 있다. 출처 Android Dev Submmit 2021 - Kotl..

LiveData를 버리고 StateFlow를 써야할까요?

Flow 비동기식으로 계산할 수 있는 데이터 스트림. Flow는 값 시퀀스를 생성하는 Iterator와 매우 비슷하지만 정지함수를 사용하여 값을 비동기적으로 생성하고 사용한다. Python의 generator와 비슷하게 이해하면 될 듯. 생산자: 스트림에 추가되는 데이터를 생산. 코루틴 덕분에 비동기적으로 생산도 가능. (Remote Datasource) 중개자(*optional): 스트림에 내보내는 각각의 값이나 스트림 자체를 수정할 수 있다. 소비자: 스트림의 값을 사용한다. 생산자는 저장소, 소비자는 UI 인터페이스라고 받아들일 수 있다. 하지만 UI 레이어가 사용자 입력이벤트의 생산자 역시 될 수 있다. StateFlow의 특징 항상 값을 가지고 있다. 단 하나의 값만을 가진다. 여러 옵저버를 가..