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

컴포즈에서 폰트 + 타이포그래피를 커스텀해보자

쉬운 방법부터 Jetpack Compose 가 권장하는 사용법까지...

 

순서 

  1. 텍스트 스타일 인라인 지정
  2. FontFamily
  3. Material 제공 Typography 
  4. Material 상속, Custom typography

 

예시로 사용한 노토산스 폰트는 웨이트별로 아래 링크에서 다운받을 수 있다.

https://fonts.google.com/noto/specimen/Noto+Sans+KR 

 

Noto Sans Korean - Google Fonts

Noto is a global font collection for writing in all modern and ancient languages. Noto Sans KR is an unmodulated (“sans serif”) design for the Korean language u

fonts.google.com

 

1번과 2번의 프리뷰!

 

1.  텍스트 스타일 인라인 지정

가장 간단한 방법

폰트 리소스를 추가하고

텍스트 스타일 필드에서 손수 지정한다.

 

@Composable
fun SimpleTextStyle() {
    Text(
        text = "simple text style",
        fontStyle = FontStyle(R.font.noto_sans_kr_regular),
        fontSize = 20.sp,
    )
}

 

 

 

2. FontFamily

 

여러 폰트 리소스를 폰트 패밀리로 묶고 사용하기!

 

폰트 패밀리 선언

val NotoSans = FontFamily(
    Font(R.font.noto_sans_kr_regular, FontWeight.Normal),
    Font(R.font.noto_sans_kr_medium, FontWeight.Medium),
    Font(R.font.noto_sans_kr_bold, FontWeight.Bold),
)

 

 

폰트 패밀리 사용예

@Composable
fun FontFamilyText() {
    Column {
        Text(
            text = "font family regular",
            fontFamily = NotoSans,
            fontWeight = FontWeight.Normal,
        )
        Text(
            text = "font family medium",
            fontFamily = NotoSans,
            fontWeight = FontWeight.Medium,
        )
        Text(
            text = "font family bold",
            fontFamily = NotoSans,
            fontWeight = FontWeight.Bold,
        )
    }
}

폰트 패밀리를 불러오는 부분이 훨씬 간단해졌다.

 Text 의 다른 필드들을 이용해 size, color 등을 지정할 수 있다.

 

 

3. Material 제공 Typography 

구글이 간편한 디자인을 위해 제공하는 Material Theme 을 사용하고있다면 미리 선언 된 타이포그래피를 사용할 수 있다.

 

미리보기...

 

주의) 최상위 스크린을 MaterailTheme 으로 감싸주어야 제대로 된 결과물을 볼 수 있다.

(여기서는 프리뷰를 MaterialTheme 으로 감싸주었음)

@Composable
fun MaterialTypo() {
    Column {
        Text(
            text = "material text h4",
            style = MaterialTheme.typography.h4
        )
        Text(
            text = "material text body1",
            style = MaterialTheme.typography.body1
        )
    }
}

@Preview(showBackground = true)
@Composable
fun PreviewMaterial() {
    MaterialTheme { // 잊지말자앗
        Column(
            modifier = Modifier.padding(10.dp),
            verticalArrangement = Arrangement.spacedBy(10.dp)
        ) {
            MaterialTypo()
        }
    }
}

material h4, body1

 

 

4. Material 상속, Custom typography

그러나 주어진 타이포그래피 안에서만 디자인이 나올리가 없다

개발자가 스스로 타이포를 선언해서 비슷한걸 묶어쓸수도 있겠고, 디자인단에서 정의 된 타이포가 내려올 수도 있겠지

 

이를위해 나는 Material 을 상속하는 Custom Theme 을 선언하고

타이포그라피 객체는 커스텀을 사용했다.

 

또한 타이포그래피는 내용이 바뀔 일 없는 객체이므로 CompositionLocalProvider 로 감싸주었다. 

 

타이포그래피 선언하기

https://developer.android.com/jetpack/compose/designsystems/material3#defining_typography

 

Material Design 3 in Compose  |  Jetpack Compose  |  Android Developers

Material Design 3 in Compose Stay organized with collections Save and categorize content based on your preferences. Jetpack Compose offers an implementation of Material Design 3, the next evolution of Material Design. Material 3 includes updated theming, c

developer.android.com

추가설명

https://developer.android.com/jetpack/compose/compositionlocal?hl=ko#intro 

 

CompositionLocal을 사용한 로컬 범위 지정 데이터  |  Jetpack Compose  |  Android Developers

CompositionLocal을 사용한 로컬 범위 지정 데이터 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. CompositionLocal은 암시적으로 컴포지션을 통해 데이터를 전달하

developer.android.com

 

val LocalReplacementTypo = staticCompositionLocalOf {
    HolsuiTypography()
}

@Composable
fun MyTheme(content: @Composable () -> Unit) {
    CompositionLocalProvider(
        LocalReplacementTypo provides myTypography
    ) {
        MaterialTheme(
            content = content,
        )
    }
}

object MyTheme {
    val typography: HolsuiTypography
        @Composable
        get() = LocalReplacementTypo.current
}

 

Typo Data class

@Immutable
data class HolsuiTypography(
    val myTypo2: TextStyle = TextStyle.Default,
    val myTypo1: TextStyle = TextStyle.Default,
    )
    
val fontFamily = FontFamily(
    listOf(
        Font(R.font.noto_sans_kr_regular, weight = FontWeight.Normal),
        Font(R.font.noto_sans_kr_medium, weight = FontWeight.Medium),
        Font(R.font.noto_sans_kr_bold, weight = FontWeight.Bold),
    )
)    

internal val myTypography = HolsuiTypography(
      defaultFontFamily = fontFamily,
      myTypo2 = TextStyle(
        fontFamily = fontFamily,
        platformStyle = platformTextStyle,
        fontSize = 14.sp,
        lineHeight = 18.sp,
        fontWeight = FontWeight.Normal
    ),
    myTypo1 = TextStyle(
        fontFamily = fontFamily,
        platformStyle = platformTextStyle,
        fontSize = 24.sp,
        lineHeight = 34.sp,
        fontWeight = FontWeight.Medium
    ),
)

 

사용할 때

 

주의) 얘도 최상위 스크린을 MyTheme 으로 잘 감싸주자

@Composable
fun CustomTypo() {
    Column {
        Text(
            text = "custom text my typo1",
            style = MyTheme.typography.myTypo1
        )
        Text(
            text = "custom text my typo2",
            style = MyTheme.typography.myTypo2
        )
    }
}

@Preview(showBackground = true)
@Composable
fun PreviewCustomTheme() {
    MyTheme { // 이거 빠지면 도로묵
        Column(
            modifier = Modifier.padding(10.dp),
            verticalArrangement = Arrangement.spacedBy(10.dp)
        ) {
            CustomTypo()
        }
    }
}

 

처음에는 조금 번거로우나 성능에도 좋고 유지보수도 편하다!

 

 

 

잘못된 내용이나 개선점 댓글로 알려주시면 감사드리겠슴다.

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

+ Recent posts