최근 Android Studio 에서 새로운 프로젝트를 만들면 다음과 같은 에러가 나면서 빌드가 되지 않는 경우가 잦습니다. Execution failed for task ':app:kaptGenerateStubsDebugKotlin'. > 'compileDebugJavaWithJavac' task (current target is 1.8) and 'kaptGenerateStubsDebugKotlin' task (current target is 17) jvm target compatibility should be set to the same Java version. Consider using JVM toolchain: * Try: > Run with --info or --debug option...
Android | ViewModel은 어떻게 관리되는가
왜 ViewModel 이여야 하는가 Android Developers, ViewModel 개요 안드로이드 애플리케이션을 개발하거나 사용하면서, 화면이 회전되거나 오랫동안 애플리케이션을 사용하지 않는 경우 UI 관련 데이터가 삭제 되는 경험을 한적이 있을 것이다. 우리는 그러한 경우 onSaveInstanceState 함수에서 데이터를 저장했다가, onCreate 함수에서 기 저장된 데이터가 있는 경우 데이터를 복원하는 방식으로 문제를 해결해왔다. 이 문제 해결방식은 실제로 잘 동작하며 오랫동안 굳혀진 방법이다. 단순한 Input 값을 저장하고 복원하는 작업에서는 이러한 방식이 큰 문제가 없을 것이다. 다만, 비트맵과 같이 다소 큰 데이터를 직렬화하고 역직렬화 하기에는 부담스러운 부분이 있다. 대부분의 경우...
Jetpack Compose | ModalBottomSheet(M3)
최근 M3에서 제공되는 ModalBottomSheet를 이용하게 되었는데, BottomSheet뒤에 있는 뷰가 터치되지 않는 문제가 있었다. 어떤 식으로든 BottomSheet의 컨텐츠가 보이지 않을 때는 이를 보이지 않게 해야겠다는 생각이 들었다. BottomSheetState의 targetValue와 currentValue 변수 상태에 따라서 ModalBottomSheet 컴포저블 함수를 보이지 않게 하여 문제를 해결할 수 있었으나, 애니메이션과 시간 차가 있어서 그런지 BottomSheetLayout이 열고 닫히는데 부자연스러운 점이 있었다. 그래서 ModalBottomSheet의 표시 여부를 나타내는 Boolean 타입의 State를 만들고 이를 LaunchedEffect 를 이용해서 상태에 따라...
Jetpack Compose | Composable 함수에서의 ViewModel 사용
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1 Jetpack Compose의 Composable 함수에서 viewModel() 함수로 뷰 모델에 액세스 하기 위해 앱 단위 build.gradle 에 다음 라이브러리를 추가한다. @Composable fun Test(testViewModel: TestViewModel = viewModel()) { Text(text = testViewModel.str) } 라이브러리 추가 이후 Jetpack Compose로 UI를 구성하는 과정에서 다음과 같이 ViewModel을 참조할 수 있다. 그러나 매개 변수로 전달된 View Model을 하위 Composable 함수에 전달 해서는 안 된다...
Jetpack Compose | 밀어서 삭제 (SwipeToDismiss) 구현
SwipeToDismiss(밀어서 삭제) 방식은 리스트에서 아이템을 삭제하거나, 좋아요나 플레이리스트 등 특정 그룹에 추가하는 기능을 구현할 때 용이하다. Material 라이브러리에서는 이를 쉽게 제작할 수 있도록 SwipeToDismiss 라는 Composable 함수를 지원한다. 작성 방법이 쉽기 때문에 금방 따라 작성할 수 있다. val dismissState = rememberDismissState(confirmStateChange = { if (it == DismissValue.DismissedToStart) { /** * Dismiss 되었을 때 작업할 코드 작성 */ } true }) SwipeToDismiss(state = dismissState, directions = setOf(...
Jetpack Compose | Compose를 이용하는 BaseFragment
Compose 도입 이전에도 Activity 와 Fragment, ViewModel 등 공동으로 적용되어야 하는 부분에 대해서 Base 클래스를 만들어왔다. 무엇보다도 Compose를 이용하여 UI를 구성 할 때, Theme를 일괄적으로 적용하기 위한 작업이 필요했다. Compose로 구성되는 Fragment의 BaseFragment 부모 클래스를 다음과 같이 작성해보았다. 기존 BaseFragment가 있기 때문에 이름은 ComposeBaseFragment 정도로 명명했다. abstract class ComposeBaseFragment<R : BaseViewModel> : Fragment() { abstract val viewModel: R @Composable abstract fun...
Jetpack Compose | CoordinatorLayout 내 ComposeView 스크롤 문제
<androidx.coordinatorlayout.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" app:elevation="0dp" /> <androidx...
Firebase Firestore | 문서 시각 검증
서비스에서 악성 사용자를 일정 시간 동안 차단하거나, 회원권이나 쿠폰의 유효 기간을 검증, 시각에 따라 특정 기능을 제한하는 경우에 시간 유효성을 검증해야 할 필요가 있다. 이 때, 클라이언트에서 제공하는 시간 정보를 사용하게 되면 이용자가 쉽게 조작할 수 있게 된다. JavaScript의 Date 클래스, Java의 currentTimeMillis 함수 처럼 시스템의 시간을 가져오는 함수를 위 작업을 수행하는 이용하면 기기의 시간이 변경되는 것 만으로도 큰 문제를 야기할 수 있다. 현재 서버 시각 삽입하기 Firebase 의 Firestore 나 Realtime Database 에서는 FieldValue (Firestore) 혹은 ServerValue (Realtime Database)를 이용하여 현재...