Seoplee
개발의 섭리, Seoplee의 개발
Seoplee
  • 분류 전체보기 (54)
    • Android (26)
      • Architecture (12)
      • Compose (0)
      • Tips (11)
      • 트러블슈팅 (3)
    • IOS (1)
      • Tips (1)
    • Kotlin (1)
    • Coroutine (3)
      • Flow (3)
    • RxJava (12)
    • CI&CD (1)
    • WEB (8)
    • Network (1)
    • ETC (1)
    • (임시) (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Seoplee

개발의 섭리, Seoplee의 개발

Android/Tips

Android 12 이상 SplashScreen 대응하기 (올바른 SplashScreen 구현하기)

2022. 5. 10. 02:48

SplashScreen의 구현에 앞서, 우선 Splash가 왜 필요할까?

 

기본적으로 모든 앱은 실행하면 사용자에게 보여주기까지 데이터를 불러오는 시간이 필요하다. 앱이 실행되는 상태에는 Cold Start, Warm Start, Hot Start 총 3가지가 존재하며, Cold와 Warm 상태일 때 앱을 준비하는 시간이 필요하다.

(앱의 실행상태 3가지에 대해 자세한 설명은 이곳 에 설명이 잘 돼있으니 참조하자.)

 

Splash 화면이 없을 때의 앱 실행 모습을 보자.

 

최초의 View가 나오기 전, 아무것도 없는 화면이 먼저 나온다.

Hello World라는 TextView를 가지고 있는 최초의 View를 보여주기 전에, 앱을 실행하기 위한 준비를 하는 시간(앱 객체 생성, 메인 스레드 시작, 액티비티 초기화, 뷰 붙이기 등)이 필수적으로 존재할 수밖에 없다. 때문에 이 앱이 지금 실행 중이고, 실행을 위해 백그라운드에서 어떤 작업을 진행 중이다. 라는 것을 명시적으로 보여주기 위해 Splash 화면을 구현하는 것이 일반적이다.

 

Splash를 추가하면, 훨씬 자연스럽게 표현할 수 있다.

그러나, 일반적으로 많이 사용되는 SplashActivity를 만들고 Splash화면을 가지는 layout을 그리는 사용하는 방법을 쓰게되면, 아이러니하게도 처음 보여줬던 화면과 같은 방식으로 앱이 실행된다. SplashActivity에서 데이터를 로드하는 것과 별개로, 기기가 SplashActivity 자체를 그릴 준비를 해야 하기 때문이다.

 

이 앱은 과연 올바른 SplashScreen을 구현했다고 할 수 있을까?

즉 별도의 레이아웃 파일을 가지는 SplashActivity 구현은 제대로 SplashScreen을 구현했다고 보기 힘들다. 그래서 다음과 같이 레이아웃 파일을 가지는 SplashActivity를 만드는것이 아니라, windowbackground값을 가지는 Theme을 작성하여 앱 실행 시의 테마로 사용하여 앞서 말한 하얀 공백의 화면을 노출시키지 않는 방법을 사용하는 경우도 있다. 

 

  <style name=”AppTheme.Launcher”>
    <item name=”android:windowBackground”>@drawable/splash_logo</item>
  </style>

그러나 이 경우에는 애니메이션 적용이 어렵다는것, Splash단계에서 서버통신이나 내부 DB 등에서 데이터를 가져오고 준비하는 시간이 필요한 경우를 처리하기 곤란하다는 점이 존재한다. 이 방법은 단지 activity을 그리기 전 배경화면에 해당 이미지를 잠시 보여줄 뿐이기 때문이다.

 

실제로 구글에서 한때 Splash 화면을 구성하는것을 안티패턴이라고 한적이 있다고 한다.

 

이러한 문제들 때문인지 Android12 이상부터 해당 이슈들에 대응할 수 있는 Splash API가 등장하였다.

 

Android12 SplashScreen 예제

Android12 부터는 개발자가 따로 SplashScreen을 개발하지 않아도, 모든 앱의 아이콘을 이용하여 자동으로 SplashScreen을 실행한다.

 

그러나 문제는 Android12 이상의 기기에서 기존 SplashScreen을 구현해놓은 앱을 실행하면, 개발자가 만들어둔 SplashScreen + 자동으로 생성되는 SplashScreen이 중복해서 나타나기 때문에 이에 반드시 대응을 해주어야 한다.

 

다음과 같이 Splash Api 의존성을 추가해준다. 작성일 기준 최신 버전은 1.0.0-beta02이다.

// Splash Api
implementation "androidx.core:core-splashscreen:$splash_version"

스플래시 화면을 구성할 Theme를 만들어준다. 해당 테마는 Theme.SplashScreen을 부모로 가지며, postSplashScreenTheme속성을 통해, 스플래시가 끝나고 난 다음 사용할 테마를 지정한다. 만약 스플래시 화면에 표현해줄 아이콘이 애니메이션 파일이라면, duration값을 설정해줄 수 있다.

<style name="Theme.Bookwhale.Splash" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/white</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash_logo</item>
    <item name="windowSplashScreenAnimationDuration">200</item>
    <item name="postSplashScreenTheme">@style/Theme.Bookwhale</item>
</style>

다음과 같이 manifest 파일에 등록한다.

<manifest>
   <application android:theme="@style/Theme.Bookwhale.Splash">
    <!-- or -->
        <activity android:theme="@style/Theme.Bookwhale.Splash">
...

SplashScreen을 구성하는 화면은 다음과 같이 이루어져 있다.

Splash Screen의 기본 구성 (출처: https://developer.android.com/guide/topics/ui/splash-screen)

1. 아이콘은 Vector Drawable이어야 하며, 정적이거나 애니메이션 파일 모두 사용될 수 있다. 지속시간은 무제한으로 할 수 있지만, 1,000밀리 초를 초과하지 않는 것을 권장한다. 별도로 지정하지 않을 시 앱의 실행 아이콘을 사용한다.

2. 아이콘 배경은 선택사항이며 아이콘과 4. windowBackground 화면과 대비가 더 필요할 경우 사용할 수 있다. adaptive icon을 사용 중이라면 windowBackground와 대비가 충분할 경우 배경이 표시된다.

3. 배경의 1/3을 가린다.

4. 배경은 단일 색상으로 구성되며 별도로 설정하지 않을 경우 기본값으로 사용된다.

 

스플래시 화면은 생명주기 중 onCreate에서 표시해준다.

override fun onCreate(savedInstanceState: Bundle?) {
    installSplashScreen()
    super.onCreate(savedInstanceState)

일반적으로 사용하는 것처럼 특정 작업이 진행되는 동안은 계속 SplashScreen을 보여주어야 한다면 다음과 같은 방법으로 작업이 끝날 때까지 SplashScreen을 노출시킬 수 있다.

override fun onCreate(savedInstanceState: Bundle?) {
    installSplashScreen()
    super.onCreate(savedInstanceState)

    // Set up an OnPreDrawListener to the root view.
    val content: View = findViewById(android.R.id.content)
    content.viewTreeObserver.addOnPreDrawListener(
        object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                // 작업 완료 트리거
                return if (isDone) {
                    // 작업이 완료되면 스플래쉬 화면을 종료한다
                    content.viewTreeObserver.removeOnPreDrawListener(this)
                    true
                } else {
                    // 작업이 진행중이면 계속 표시한다
                    false
                }
            }
        }
    )
}

SplashScreen을 종료하는 애니메이션을 추가하고 싶다면 다음과 같이 작성하면 된다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ...

    // Add a callback that's called when the splash screen is animating to
    // the app content.
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        // Create your custom animation.
        val slideUp = ObjectAnimator.ofFloat(
            splashScreenView,
            View.TRANSLATION_Y,
            0f,
            -splashScreenView.height.toFloat()
        )
        slideUp.interpolator = AnticipateInterpolator()
        slideUp.duration = 200L

        // Call SplashScreenView.remove at the end of your custom animation.
        slideUp.doOnEnd { splashScreenView.remove() }

        // Run your animation.
        slideUp.start()
    }
}

토이 프로젝트에 다음과 같이 적용하였다.

 

Splash 중 유저 데이터를 성공적으로 받아온 경우 MainActivity로 진입
Splash중 유저 데이터가 없을 경우 LoginActivity에 잔류 (앱 기본 진입점)

 

Reference:

https://developer.android.com/guide/topics/ui/splash-screen

 

Splash screens  |  Android Developers

Splash screens Important: If you have previously implemented a custom splash screen in Android 11 or lower, you'll need to migrate your app to the SplashScreen API to ensure that it displays correctly in Android 12 and higher. For instructions, see Migrate

developer.android.com

https://kwongdevelop.tistory.com/34

 

App Startup time

사용자는 앱이 빠르게 로드되길 바라는데 시작 시간이 느리면 구글 플레이 스토어에서 낮은 점수를 받을 수도 있고,, 앱을 아예 사용안할 수도 있으니 앱 시작 시간을 최적화하는데 도움을 주겠

kwongdevelop.tistory.com

 

저작자표시 (새창열림)

'Android > Tips' 카테고리의 다른 글

startActivityForResult Deprecated  (0) 2022.02.18
CompileSdk, TargetSdk, MinSdkVersion 비교  (0) 2021.12.16
툴바(ToolBar) 구현, Toolbar VS Layout  (0) 2021.12.13
RecyclerView에 animation 효과 주기  (0) 2021.12.04
Recyclerview adapter 재활용하기  (0) 2021.11.15
    'Android/Tips' 카테고리의 다른 글
    • startActivityForResult Deprecated
    • CompileSdk, TargetSdk, MinSdkVersion 비교
    • 툴바(ToolBar) 구현, Toolbar VS Layout
    • RecyclerView에 animation 효과 주기
    Seoplee
    Seoplee
    개발공부를 하며 기록할만한 것들을 정리해놓은 블로그입니다.

    티스토리툴바