728x90

웨어러블과 모바일 앱을 멀티모듈을 이용해 구성하던 중,

 

app, wearable app 과 같은 상위 level 에 포함시켜야 할 

data, domain 모듈을 app 모듈 내부에 만들었음을 깨달았다

니가 왜 거기에있어?ㅠ

멍청이…

 

그래서 rename 이나 디렉터리상에서 옮기기를 시도해보았지만 잘 되지 않았고.. 

Project Sturcture 의 module 탭에서도 Add, Delete 가 있을 뿐 Move 가 없었다

 

…그래서 해결책은…

 

1. 파인더등에서 디렉터리를 째로 옮기거나 rename 을 통해 ‘:app’ (< 상위 루트 이름)을 제거한다.

 

2. settings.gradle 파일에서 include 된 모듈이름도 변경해준다!

 

3. 당연히 include 시에 :app:뭐시기 -> :뭐시기  변경도 해주어야한다

 

4. Sync 잊지말기!

 

5. 만약에 안나오면 File -> Invalidate Caches 

 

 



 

호호 모듈 옮기기 성공

 

728x90
728x90

[현상]

개인프로젝트 중 힐트 어노테이션 의존성(?)을 추가하니 빌드에러가 난다..... 

    ksp(libs.hilt.android.compiler)

 

[원인]

KSP 는 아직 힐트를 지원하지 않음

 

https://issuetracker.google.com/issues/179057202

 

Google Issue Tracker

 

issuetracker.google.com

 

증말 너무한다잉

 

 

[해결]

kapt 로 돌아가야한다 뿌엥...

 

Before

plugins {
	// ...
    id("com.google.devtools.ksp")
}

dependencies {
	// ...
        ksp(libs.hilt.android.compiler)
}

 

After

plugins {
	// ...
    kotlin("kapt")
}

dependencies {
	// ...
        kapt(libs.hilt.android.compiler)
}

 

혹시 추가 설명이 필요하신 분은 아래 링크 참고 

 

https://kotlinlang.org/docs/kapt.html#annotation-processor-arguments

 

kapt compiler plugin | Kotlin

 

kotlinlang.org

 

그렇게... 나의 빌드속도 향상이여...안녕히... 

android dev 의 'Migrate from kapt to KSP' 문서에서 발췌..

 

모듈화가 되어있기는 하나 Hilt 는 뭐 거의 다 쓰이기때문에.....하..... 

그냥 업뎃을 기다려야겠다

 

그래서 프로덕션에서는 maintenance 상태인 kapt 를 쓰는구나....ㅎ

728x90
728x90

문제

 

테스트 빌드중에 

connectedDebugAndroidTest 에서 영원한 로딩에 굴레에 갇히는 일이 있었다.. (테스트빌드 말고 그냥빌드는 잘됨....& unit test 도 잘됨.... instrumental test만 난리남)

 

Androidx.test.espresso:espresso-core

 

해당 의존성을 3.5.0 -> 3.4.0 으로 내리니 빌드가 정상적으로 되긴 했지만

해당 라이브러리가 배포된지도 좀 되었고 다른 프로젝트에서는 잘 되기에… 

다른 문제가 있겠거니 해서 열심히 뒤적거렸다. 

 

해결 

 

힐트 테스트 디펜던시가 implementation 으로 되어있는것을 발견.. 

공식문서에는 테스트 스코프로 명시되어있다 

 

 

https://developer.android.com/training/dependency-injection/hilt-testing?hl=ko#testing-dependencies

 

Hilt 테스트 가이드  |  Android 개발자  |  Android Developers

Hilt 테스트 가이드 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Hilt와 같은 종속 항목 삽입 프레임워크를 사용하여 얻을 수 있는 이점 중 하나는 코드를

developer.android.com

 

이를 testImplementation 과 androidTestImplementation 으로 교체해주니 빌드도 테스트도 잘 된다. 

 

 

dependencies {
// AS-IS
	implementation("com.google.dagger:hilt-android-testing:2.44")

// TO-BE
    testImplementation("com.google.dagger:hilt-android-testing:2.44")
    androidTestImplementation("com.google.dagger:hilt-android-testing:2.44")
}

 

공식문서를 잘 보자 흑흑

해결하는데 이틀꼬박걸림 

 

아래는 유입을 위한 추적하면서 마주친 에러메시지들 

 

더보기

로그캣

 

java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/test/platform/io/PlatformTestStorageRegistry;

 

 

테스트 실패 메시지 (무한로딩걸리는 부분)

 

Execution failed for task ':app:connectedDebugAndroidTest'.

 

 

디펜던시 오류 메시지

 

Cannot find a version of 'androidx.test:monitor' that satisfies the version constraints:

   Dependency path ':app:unspecified' --> 'androidx.test:monitor:1.6.1'

   Constraint path ':app:unspecified' --> 'androidx.test:monitor:{strictly 1.4.0}' because of the following reason: debugRuntimeClasspath uses version 1.4.0

728x90
728x90

Hilt 를 이용한 DI에서,

구현체를 만들 때 3가지 어노테이션을 사용할 수 있다.

 

간단히 플로우차트로 나타내면 아래와 같다.

 

 

 

가장 간단한 케이스로, constructor 가 존재하여

1. 모듈이 필요없는 의존성 주입

@Inject constructor(param….) 

class DateFormatter @Inject constructor() {

    @SuppressLint("SimpleDateFormat")
    private val formatter = SimpleDateFormat("d MMM yyyy HH:mm:ss")

    fun formatDate(timestamp: Long): String {
        return formatter.format(Date(timestamp))
    }
}

위 코드는 구글의 Hilt codelab Solution에서 가져왔다.

 

2. 모듈이 필요한 의존성 주입 (constructor 없음)

 

Constructor가 없는 이유에 따라 해결법이 갈린다.

a. 외부라이브러리임, 빌더패턴임

b. Interface 임

 

@Module, @InstallIn(...) 의 어노테이션이 있는 

모듈 클래스 내부에 @Provides, @Binds 어노테이션이 붙은 함수를 이용한다.

주의 - 둘은 섞어서 쓸 수 없음...

 

2-a. @Provides 어노테이션

외부라이브러리나 빌더패턴의 경우에 사용

코드랩 솔루션 일부 (ApplicationComponent 는 현재 Deprecated -> Delete 되었으나 이 글은 @Provides 를 설명하는 글이지 scope를 설명하는 글이 아니고, 코드랩에는 아직 이게 나와있어서 그냥 복붙,,, 이제 쓸일없는 코드)

@InstallIn(ApplicationComponent::class)
@Module
object DatabaseModule {

    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext appContext: Context): AppDatabase {
        return Room.databaseBuilder(
            appContext,
            AppDatabase::class.java,
            "logging.db"
        ).build()
    }
    //...
}

 

 

2-b. @Binds 어노테이션

 

인터페이스를 주입할 때 필요한 정보를 제공하는 역할.

추상함수 형태로 제공 (따라서 이것을 포함하는 Module class역시 추상 class 가 된다.) -> Binds 와 Provides 를 섞어쓸 수 없는 이유

역할 : 인터페이스클래스와 구현체 클래스를 알려줌 

  • 리턴타입 : 어떤 인터페이스 인스턴스를 제공하는지 알려줌
  • 파라미터 타입 : 인터페이스를 상속하는 녀석들중에 어떤 구현체를 제공할지 Hilt 에 알려줌

 

@InstallIn(ActivityComponent::class)
@Module
abstract class LoggingInMemoryModule{

    @ActivityScoped
    @Binds
    abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource) : LoggerDataSource
}


아마도 함수가 사용안됨으로 표시될건데

@Inject 하면 그렇게 표시되더라도 Inject 하는 곳으로 안내됨..(?) 즉, 신경쓸필요없음

 

 

위의 세 방식으로 힐트에게 의존성 주입 방법에 대해 알려주었다.

 

Binds 나 Provides 는 같은 인터페이스/클래스에 대해 각기 다른 구현을 여러개 가질 수 있다.

이렇게 여러 구현이 있는 경우 @Qualifier 로 어떤 구현을 사용할지 구분할 수 있다.

 

 

나도 힐트 초보자이고, 사용법 가이드라기보다는 개념을 이해하기위해 쓴 글이기때문에 엄밀하지 않은 부분이 있을 수 있다.

틀린부분을 댓글로 달아주시면 감사감사... 

 

더보기
728x90
728x90

Hilt codelab 을 진행하다가 위와같은 오류를 만났다

error: cannot find symbol @dagger.hilt.InstallIn(value = {ApplicationComponent.class})

https://developer.android.com/codelabs/android-hilt?hl=ko#6 

 

Android 앱에서 Hilt 사용  |  Android 개발자  |  Android Developers

이 Codelab에서는 Hilt를 사용하여 종속 항목 삽입을 실행하는 Android 앱을 빌드해 보겠습니다.

developer.android.com

 

 

사실 ApplicationComponent.class가 애초부터 import 가 안되었음ㅎ

해당 클래스는 대거에서 특정시점에 Deprecate -> Delete 되었다고 한다.

SingletonComponent로 대체되었다고..

실제 상황이면 대체 클래스를 이용하겠지만.. 이건 코드랩이니까 최대한 코드랩과 싱크를 맞추기 위해 다운그레이드하는걸로..

 

Hilt version 을 바꾸어주니 임포트 완... 해결

 

근데 구글은 라이브러리 업뎃 푸시하고 빌드를 안해본건가....??????

 

build.gradle(project)

 

변경전 

ext.hilt_version = '2.40.1'

변경후

ext.hilt_version = '2.28.3-alpha'

 

이렇게 버전을 바꿔주면 코드랩을 끝까지 따라갈 수 있다.....

 

출처

 

728x90
728x90

Jetpack Compose 실무 도입 후기

 

기존 뷰를 사용하던 팀에서 작년9월부터 현재까지 약 10개월간 점진적으로 컴포즈를 도입한 후기… (벌써 10달이나 됐어..?)

by 안드로이드 병아리 와타시..

 

9월 : 하이 컴포즈

 

실험적으로.. 로직이 비교적 간단하고, 영향력이 비교적 적은 페이지를 컴포즈로 교체해보았다.

이때 나는 컴포즈 코드랩 하면서 구경함… 미지의 세계…

기존 뷰를 위한 프레젠테이션 모델을 구상할 때 딱히 Stability 를 생각하지 않았으므로, 컴포즈만을 위한 거의 비슷한~ 모델을 다시 구성했다… 물론 기존 모델을 건들면 깨끗은 했겠지만 영향력이 너무 커서 안정성을 위한 투트랙….

괜찮았을것도 같지만 상용서비스까지 나가진 못했다. 그냥 체험해본것으로…

 

10월 : 컴포넌트화?

 

반복적으로 사용되는 버튼을 컴포넌트화 해보기로 했다.

이건 디자인 팀에서 컴포넌트화를 강력하게 미는것과 맞물려서 시도했던건데

뷰 내부까지 컴포즈 컴포넌트를 쓰는것은 수고에비해 얻는게 없는것같아서… 일단 컴포즈를 사용중인 부분만 먼저 컴포넌트화 했다.

소통도 많이하고 고민도 많았는데 이후 컴포넌트에 예상치못한 베리에이션들이 생기면서 잡음이 많았던거같다.

 

12월 : 상용출격!!!

 

상용서비스에 드디어 컴포즈 출격…

기획단에서 엎어버린 바람에 몇달 못가고 사라진 스크린이지만.. 암튼 한 스크린 전체에 컴포즈가 도입되었다

 

이때까지도 컴포즈에 가장 관심이 많은 팀원분만 홀로 외로운 컴포즈길을 걸었음

 

김OO : 컴포즈 사세요.. 컴포즈 좋아요....

 

2월  : 나작컴(나의작은컴포즈)

 

나에게도 컴포즈의 바람이(?) 불어오기 시작

본격적으로 메인 피쳐에 컴포즈를 도입하기 시작했다

한땀한땀 작성하느라 시간은 좀 걸렸다…. 상태관리도 미숙하고…

이때 각 컴포넌트에서 뭘 조정할 수 있는지 보려고 android developers 문서를 참 많이봤는데

꼭 필요한 문서긴 하지만 문서를 맨날 보는거보다는… 급할때는 해당 컴포저블 파라미터 뭐뭐있는지 보면서 상황파악하는게 더 빠른거같다(개인적인생각...)

UI state 을 끌어올려서 애니메이션이나 스크롤을 컨트롤 하는 문제가 까다로웠다 ㅠ

 

6월 : 나작띰

 

디자인쪽에서 컨벤션이 좀 완성되어서 Material Theme3 을 상속하는 서비스 자체 Theme 을.. Font 부터 도입하였다

Theme 을 컴포넌트마다 씌워놨다가 감사하게도 리뷰어택을 맞고… 

스크린단위로 바꿈…. 



~현재

 

컴포즈를 얼레벌레 도입해서 팀원들과 리뷰를 주고받으며 어떻게 잘 끌고오고 있는데,

이제는… 모두… 컴포즈 없이는… 살수없는몸이 되어버렸음…. 

일단 구현시간이 압도적으로 빠르고, 디자인 수정도 대체로 쉽다..

그리고 난 갠적으로 프리뷰기능 사랑함… 이걸로 좀 까다로울거같은 상호작용을 먼저 구현해보고.. 폰에서 만져보고… 사이즈보고 일에 착수할 수 있는거 너무좋당..

또, 보일러플레이트 코드가 적고 (특히 리사이클러뷰 미친놈)

UI업데이트가 이런저런 복잡한 길을 타고 이루어지는게 아니라 깔쌈하게 상태를따라가니 상태 업데이트에 집중할 수 있어 디버깅도 쉽다고 느낀다.

 

조금 아쉬웠던건 Pager…가 아직 미완성느낌이 좀 있어서… 기존 뷰바인딩과 섞어서 사용하는 부분이 아직 남아있다.. TextField 랑 씨름한적도 있었는데 이것도 아직 완성품은 아닌 느낌이다…(deprecate 되었다가 다시 살아났다가 이젠 디폴트 false 가 되신 includeFontPadding) 

뭐 텍스트 인풋창은 평생의 숙제긴하지… 

 

그리고 컴포즈의 아쉬움은 아니고, 이미 꽤 디벨롭된 프로젝트라면 겪기 쉬운 문제라고 생각이 드는데, 마이그레이션하면서 뷰와 컴포즈를 위한 프레젠테이션 모델이 분리되면서(눈으로 보기엔 똑같은??) 샷건수정이 빈번하게 일어나기도 했다.

 

 

그러나 암튼, 과거로 돌아가서 컴포즈로 마이그레이션 다시 할거냐고 묻는다면 나는 YES!!!






728x90
728x90

출처 : https://developer.android.com/jetpack/compose/state?hl=ko#restore-ui-state 

 

상태 및 Jetpack Compose  |  Android Developers

상태 및 Jetpack Compose 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 앱의 상태는 시간이 지남에 따라 변할 수 있는 값을 의미합니다. 이는 매우 광범위한 정

developer.android.com

 

이전글에서는 선언형 UI가 무엇인지, 재구성과 부작용이 무엇인지 간단히 살펴보았다. 

오늘은 콤포오즈 사용에 있어 빠질 수 없는 상태에 대한 이해..

 

상태(State) 

시간이 지남에 따라 변할 수 있는 값

ex) 

  • 네트워크 연결을 설정할 수 없을 때 표시되는 스낵바
  • 블로그 게시물 및 관련 댓글
  • 사용자가 클릭하면 버튼에서 재생되는 물결 애니메이션
  • 사용자가 이미지 위에 그릴 수 있는 스티커

 

상태 및 구성

Composable 을 업데이트 하려면 새 인수로 동일 컴포저블을 호출해야함

 

컴포저블의 상태(State)

컴포저블은 remeber API 를 사용해 메모리에 객체를 저장할 수 있음

초기 컴포지션 중에 값을 저장하고

리컴포지션시에 이 값을 꺼내 사용

 

MutableState<T> 형식 : 관찰가능한 유형 대표(?)

 

관찰가능한 객체를 선언하는 세가지 방법

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

 

주의 : ArrayList<T>, mutableListOf() 같은 mutable 한 객체를 상태로 사용하면 관찰이 불가하여 객체 변경 시 리컴포지션이 트리거되지 않는다. State<List<T>>, listOf() 등 관찰 가능한 데이터 홀더를 사용할 것! 

 

Remember 는 재구성(recomposition)시에 값을 저장하는 역할, 구성 변경 전반에서는 값을 저장하지 못하므로 

그러한 역할이 필요할 때는 remember saveable 을 사용한다.

 

Remember saveable 에는  Bundle 에 저장될 수 있는 값 형태나, 맞춤 Saver 객체가 저장된다. 

(번들에 추가할 수 없는 데이터 유형을 사용하고 싶은 경우 @Parcelize 주석, mapSaver, ListSaver 등을 이용하여 saver 객체를 만들어 저장할 수 있다.... 김 비둘기 님 피드백)




Jetpack Compose 에서 지원되는 기타 상태 유형

 

컴포즈는 state 객체를 읽어 재구성(리컴포지션)을 수행하므로 관찰 대상 데이터들을 state로 변환해주어야한다.

 

아래 유형들을 State<T> 로 변환하는 함수가 Compose 에 내장되어있음 



Flow : CollectAsStateWithLifecycle() - Android 전용

Flow : CollectAsState

LiveData : ObserveAsState()

RxJava2 : subscribeAsState()

RxJava3 : subscribeAsState()

 

이외에 다른 유형을 컴포즈와 함께 사용하기 위해 produceState API 를 이용해 직접 확장함수를 빌드해도 된다고 한다..



스테이트풀(Stateful)과 스테이트리스(Stateless)

스테이트풀 : remember 로 객체를 저장하는 컴포저블을 스테이트풀 하다고 한다.

스테이트리스 : 내부에 state 를 갖지 않는 컴포저블(파라미터로 받아서 쓰기만..)

 

스테이트풀은 호출자가 상태를 제어,관리할 수 없다 -> 스테이트풀은 호출자가 상태를 제어,관리할 필요 없을 때 쓴다

스테이트풀한 컴포저블은 밖에서 스테이트를 제어, 관리 할 수 없으므로 재사용 가능성이 적고 테스터블하지 않다. 

 

따라서 재사용을 위한 컴포저블 개발 시 스테이트풀/ 스테이트리스 모두 노출하기도 함



상태 호이스팅 

컴포저블을 스테이스리스로 만들기위해 상태를 호출자로 옮기는(끌어올리는) 패턴

내부의 상태변수를 두개의 매개변수로 바꾼다 

  1. Value : 표시될 값
  2. Event : 값 변경을 요청하는 이벤트

 

2번 Event 는 onValueChange : (T) -> Unit 형태로 많이 쓰지만 구체적 이벤트가 어울리는 경우 람다를 이용해 정의할 수 있음

 

끌어올려진 상태의 중요한 속성

  • 단일 정보 소스 - Single Source Of Truth : 버그 방지
  • 캡슐화 : 끌어올림 받은(?) 스테이트풀 컴포저블의 내부적 속성으로 이 스테이트풀 컴포저블만 상태를 수정할 수 있음
  • 공유가능 : 호이스팅 후 스테이트풀 컴포저블 내부(하위의) 다른 컴포저블에도 값을 공유할 수 있다
  • 가로채기 가능 : 호출자가 값을 먼저 보고 무시하거나 수정하는 등 결정이 가능
  • 분리됨 : 상태를 뷰모델 등 어디든지 저장할 수 있음

 

이러한 호이스팅을 통해 UI 상태를 표시하는 컴포저블과 상태를 저장하고 변경하는 앱 부분을 분리할 수 있다.

 

상태만 mock 으로 주고 이래저래 테스트도 간편하고 좋다… 

 

 

 

 

 

 

틀린내용 댓글로 달아주시면 감사합니다

 

728x90
728x90

 


잡설....

선언형 UI 인 제트팩 컴포즈

 

팀에서 프로젝트를 부분부분 컴포즈로 옮겨가고 있었는데, 이번에 새 프로젝트를 시작하게 되면서 가능하면 100% 컴포즈를 이용해보기로했다 (아직은 뷰바인딩이 더 유려한 컴포넌트도 있긴 있응게..)

 

암튼 그래서 새로운 기술스택들이 좀 추가되기도 하고, 이전에 알던걸 좀 더 잘 알아야할 필요가 느껴져서 이전에 공부하던 내용 업로드도 하고 내용 추가도 하면서 나도 공부를 좀 더 해보려함


 

오늘 내용인 컴포즈의 이해는 

 

https://developer.android.com/jetpack/compose/mental-model?hl=ko

 

Compose 이해  |  Jetpack Compose  |  Android Developers

Compose 이해 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Jetpack Compose는 Android를 위한 현대적인 선언형 UI 도구 키트입니다. Compose는 프런트엔드 뷰를 명령

developer.android.com

해당 링크 내용을 내가 다시 보고 이해하기쉽게 나름대로 정리해본것이다.

 

선언형 API 

기존의 UI : UI 위젯트리를 findViewById() 등으로 탐색하고 메서드를 호출, 위젯의 내부 상태를 수정 

선언형 API : 위젯 트리를 인스턴스화하여 UI를 초기화, 비교적 stateless 하고 getter, setter 를 노출하지 않음 (객체로 노출되지 않음), 데이터가 변하면 동일 컴포저블을 다른 param 으로 호출하여(새로운 인스턴스) 업데이트

 

@Composable : 이 함수는 데이터 -> UI 변환을 위한 함수임을 컴파일러에 알림

컴포저블은 다른 컴포저블을 호출하여 UI 계층 구조를 내보낸다.

 

뭐랄까.. 트리구조라고하니까 사과나무를 생각해보면

13번 사과를 익힌다 라고했을 때 기존 방식은 나무검색>13번사과찾아>그사과의 컬러를 레드로 set해라 

라는 느낌이라면 

컴포즈는 13번사과(익음) 을 호출하면 그냥 익은사과가 만들어지고 초록사과 자리에 들어가는 느낌

트리는 13번 사과를 다시 찾을 필요가 없으며 사과는 스스로가 무슨색인지 기억할 필요가 없다(stateless)

 

사용자와의 상호작용 

재구성(recomposition) : onClick 같은 이벤트가 발생하면 앱 상태를 변경 > 그러면 데이터가 변하고 변화 된 새 데이터가 컴포저블을 다시 호출 (위젯을 직접 찾고 수정할 필요 없음)



또한 나무는 사과들을 알아서 관리중이기에 사과를 구성한 데이터가 바뀌면 알아서 

해당 가지와 사과만 업데이트해준다.

 

재구성

 

재구성을 이해하기 전에 부작용이란?

부작용(부수효과)

부작용 : 컴포저블 함수의 범위 밖에서 발생하는 앱 상태에 관한 변경사항 

컴포저블이 아닌 앱의 나머지 부분에 표시되는 변경사항 

ex: 공유객체 속성 쓰기, 뷰모델에 업데이트, 공유 환경설정 업데이트..

 

컴포저블이 실행되면서 컴포저블 밖의 데이터를 건드는 것을 부작용이라 한다. 뭔가 부정적인 네이밍이 개념을 헷갈리게 한다 갠적으로는…. 부작용의 ‘부' 는 부정적인 의미가 아니다. 부작용의 단어정의도 혹시 도움이될까하여 첨부 

: 본래의 치료 효과 이외의 부수적인 효과가 나타나는 것이다. 부수적 효과가 도움이 된다면, 부작용은 치료 목적으로도 물론 이용할 수 있다. (출처 : 위키백과-부작용)

 

새 데이터 인풋으로인해 리컴포지션이 일어날 때, 영향을 받는 있는 함수/람다만 호출되고 나머지는 최대한 건너뛴다.

따라서 리컴포지션 시 부작용을 이용하려 하면 안된다. 



또한 코드가 반드시 표시 된 순서대로 실행되지는 않으므로 순서상 위쪽 코드의 부작용(전역변수 설정 등)을 이용해 아래쪽 코드가 활용하는 구현 또한 불가하다.

 

부작용은 onClick 등의 콜백을 이용해 트리거 되어야 한다.

 

컴포저블의 재구성 특징을 이해하고 있으면 부작용의 오남용을 막을 수 있고, 의도대로 동작하는 코드를 짜는데 도움이 된다.

 

1. 구성 가능한 함수(Composable)는 동시에 실행할 수 있음

컴포저블은 최적화를 위해 여러 다른 스레드에서 동시에 호출될 수 있음

따라서 컴포저블 람다의 변수를 수정하는 코드는 피해야함

여기저기 불려가서 엉망진창의 값이 될 수 있으니까….

 

2. 재구성은 가능한 한 많이 건너뜀

재구성 시에 최대한 많은 요소를 건너뛰므로 다시한번, 부작용이 없어야한다.

 

3. 재구성은 낙관적임

매개변수가 변경되었을 ‘수’ 있을 때마다 재구성이 시작되고, 중간에 매개변수가 또 변하면 취소>재구성이 될 수 있으므로 표시되는 UI에 종속되는 부작용이 있으면 앱 상태가 일관적이지 않을 수 있음

 

4. 구성 가능한 함수(Composable)는 매우 자주 실행될 수 있음

‘공유환경설정에서 읽기’ 등 비용이 많이 드는 작업은 백그라운드 코루틴에서 실행하고 그 결과를 매개변수로 컴포저블에 전달하여야 함.

비용이 많이 드는 작업이 컴포저블 내에 있으면 이것이 불필요하게 반복실행되면서 UI버벅임이 생길 수 있다.

따라서 비용이 많이 드는 작업은 외부 스레드로 이동시키고 mutableStateOf / LiveData 등으로 그 결과를 컴포저블에 전달해야한다.






쉽게 요약하면 내가 컴포저블을 선언은했지만, 실행,재구성하는 시점이나 횟수는 내가 통제하는 것이 아니므로 

컴포저블에 다른거 시키는건(부작용) 지양하자..  

마치 마계생물을 함부로 소환하면 안된다거나 시간축을 건드려서는 안된다는 금기같은것이지 하하

 

 

 

 

 

 

틀린내용 댓글로 달아주시면 감사합니다

 

728x90

+ Recent posts