Android/Side Projects

오늘의 명언 앱 개발하기

화요밍 2022. 2. 7. 23:05
728x90
반응형
Side Project - Today Famous Saying
화면을 스와이프하며 오늘의 명언들을 볼 수 있는 앱을 구현한 프로젝트

 

 

GitHub - hwayeon351/Today-Famous-Saying: 오늘의 명언 안드로이드 앱

오늘의 명언 안드로이드 앱. Contribute to hwayeon351/Today-Famous-Saying development by creating an account on GitHub.

github.com


학습 회고

오늘은 오늘의 명언 앱 프로젝트를 마쳤다.

Firebase Remote Config에 매개변수를 설정해서 명언과 인물을 json으로 정의하고 앱에서 받아와 명언들을 ViewPager2에 적용하였다.


오늘 공부한 내용

  • Firebase Remote Config

Firebase Remote Config는 사용자가 앱을 업데이트를 하기 위해 다운로드할 필요 없이 앱의 동작과 모양을 변경할 수 있도록 하는 클라우드 서비스이다.

Firebase Console을 사용해서 서버 측 매개변수 값을 설정하고 변경해서 앱의 기본 동작과 모양에 변화를 줄 수 있다.

Remote Config는 매개변수 값을 가져오기 또는 캐싱과 같은 중요한 작업을 처리하는 클라이언트 라이브러리를 포함한다.

 

1. 앱에 Firebase와 Remote Config SDK 추가하기

프로젝트 단의 gradle에 다음 dependency를 추가한다.

classpath "com.google.gms:google-services:4.3.5"

모듈(앱 수준) gradle에 다음 dependency들을 추가한다.

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:29.0.4')

    // Declare the dependencies for the Remote Config and Analytics libraries
    // When using the BoM, you don't specify versions in Firebase library dependencies
    implementation 'com.google.firebase:firebase-config-ktx'
    implementation 'com.google.firebase:firebase-analytics-ktx'
}

 

2. RemoteConfig 싱글톤 객체 가져오기

val remoteConfig = Firebase.remoteConfig
remoteConfig.setConfigSettingsAsync(
    remoteConfigSettings {
        minimumFetchIntervalInSeconds = 0
    }
)

minimumFetchIntervalInSeconds는 Firebase console에 업데이트된 매개변수 값을 가져오는 시점을 설정한다.

개발 단계에서는 0으로 넣어 매개변수에 업데이트가 발생할 때마다 앱을 재실행하면 바로바로 받아올 수 있도록 하였다.

 

3. Firebase Console에 매개변수 값 설정하기

 

4. 매개변수 값 가져오기 및 활성화

fetchAndActivate() 매서드를 호출해서 매개변수 값을 Firebase console로부터 가져와 앱에서 사용할 수 있다.

remoteConfig.fetchAndActivate().addOnCompleteListener {
    progressBar.visibility = View.GONE
    if(it.isSuccessful) {
        val quotes = parseQuotesJson(remoteConfig.getString("quotes"))
        val isNameRevealed = remoteConfig.getBoolean("is_name_revealed")

        displayQuotesPager(quotes, isNameRevealed)
    }
}

업데이트된 매개변수 값은 앱의 동작과 모양에 영향을 주기 때문에 UX에 방해가 되지 않을 만한 시점에서 가져온 값을 활성화 하는 것이 좋다.

나는 onCreate()에서 호출해서 앱이 처음 실행되어서 액티비티가 생성되었을 때 값을 가져오고 활성화하도록 하였다.

 

 

* minimumFetchIntervalInSeconds

앱에서 단기간에 매개변수 가져오기를 너무 많이 수행하면 호출이 제한되고 SDK는 FirebaseRemoteConfigFetchThrottledException을 반환한다.

앱 개발 단계에서는 앱을 개발하고 테스트할 때 더 빠르게 반복할 수 있도록 매개변수 가져오기와 활성화를 자주 해야할 수도 있다.

 

개발 이후 사용자가 앱을 사용하는 환경에서는 minimumFetchIntervalInSeconds는 최소 12시간이다.

그러면 실제로 fetch 호출 횟수와 관계없이 12시간 동안 백엔드 config를 한 번만 가져올 수 있다.

 

 

  • PageTransformer

PageTransformer는 visible인 페이지가 스크롤될 때 호출된다.

PageTransformer를 사용해서 커스텀으로 페이지를 넘길때 애니메이션을 적용할 수 있다.

 

명언을 하나씩 넘길 때마다 투명도가 연해지고 진해지는 애니메이션 효과를 주어 여운을 남기기 위해 PageTransformer를 사용하였다.

ViewPager에 setPagerTransformer를 호출해서 커스텀 애니메이션을 적용할 수 있다.

setPageTransformer의 내부 코드는 다음과 같다. 

public void setPageTransformer(@Nullable PageTransformer transformer) {
    if (transformer != null) {
        if (!mSavedItemAnimatorPresent) {
            mSavedItemAnimator = mRecyclerView.getItemAnimator();
            mSavedItemAnimatorPresent = true;
        }
        mRecyclerView.setItemAnimator(null);
    } else {
        if (mSavedItemAnimatorPresent) {
            mRecyclerView.setItemAnimator(mSavedItemAnimator);
            mSavedItemAnimator = null;
            mSavedItemAnimatorPresent = false;
        }
    }

    // TODO: add support for reverseDrawingOrder: b/112892792
    // TODO: add support for pageLayerType: b/112893074
    if (transformer == mPageTransformerAdapter.getPageTransformer()) {
        return;
    }
    mPageTransformerAdapter.setPageTransformer(transformer);
    requestTransform();
}

PageTransformer을 매개변수로 가지고 있는데 PageTransformer 내부는 다음과 같다.

public interface PageTransformer {

    /**
     * Apply a property transformation to the given page.
     *
     * @param page Apply the transformation to this page
     * @param position Position of page relative to the current front-and-center
     *                 position of the pager. 0 is front and center. 1 is one full
     *                 page position to the right, and -2 is two pages to the left.
     *                 Minimum / maximum observed values depend on how many pages we keep
     *                 attached, which depends on offscreenPageLimit.
     *
     * @see #setOffscreenPageLimit(int)
     */
    void transformPage(@NonNull View page, float position);
}

transformPage의 매개변수인 page는 transformation을 적용하는 페이지를 말한다.

position은 페이지의 포지션을 말하고, 0이면 front and center, 1이면 오른쪽 전체 페이지, -2이면 왼쪽 2페이지를 말한다.

 

명언이 있는 페이지를 하나씩 넘길 때마다 투명도가 연해지고 진해지는 애니메이션 효과를 주기 위해서 0, 0~1 사이, 1 이상의 포지션에 각기 다른 alpha 값을 적용해 주었다.

viewPager.setPageTransformer { page, position ->
    when {
    	#페이지의 포지션이 왼쪽 오른쪽으로 1 이상일 때, 투명도를 0으로 하여 투명하게 한다
        position.absoluteValue >= 1F -> {
            page.alpha = 0F
        }
        
        #페이지의 포지션이 0인 경우, 투명도를 1로 하여 선명하게 보이게 한다
        position == 0F -> {
            page.alpha = 1F
        }
        
        #페이지의 포지션이 0~1 사이일 때에 비례하게 투명도를 적용하여 서서히 투명하고 나타나는 효과를 적용한다
        else -> {
            page.alpha = 1F - position.absoluteValue*2
        }
    }
}

 

 

  • ProgressBar

ProgressBar는 어떤 작업의 진행도를 유저 인터페이스에 표시해준다.

ProgressBar의 종류는 Determinate Progress와 Indeterminate Progress 두 가지가 있다.

  • Indeterminate Progress

ProgressBar의 진행도를 표시하지 않아서 얼마나 걸릴지 모르는 작업에 사용할 수 있다.

싸이클이 돌아가는 애니메이션을 보여준다.

 <ProgressBar
      android:id="@+id/indeterminateBar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      />
 

 

  • Determinate Progress

작업의 진행도가 얼마나 진행되었고 남았는지를 보이고 싶다면 Determinate Progress를 사용하면 된다.

ProgressBar의 R.style.Widget_ProgressBar_Horizontal을 적용하고 progress 속성에 값을 넣어 진행도(%)를 표시할 수 있다.

 

 <ProgressBar
      android:id="@+id/determinateBar"
      style="@android:style/Widget.ProgressBar.Horizontal"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:progress="25"/>
 ​

 

오늘의 명언 앱에서는 Firebase Remote Config에서 매개변수를 불러와 활성화 시키기까지의 로딩을 표현하기 위해 Indeterminate Progress를 사용했다.

 

private val progressBar: ProgressBar by lazy {
    findViewById(R.id.progressBar)
}

뷰 바인딩을 해주고 ProgressBar가 사라져야하는 시점에 visibility 속성을 View.GONE으로 바꿔주었다.

remoteConfig.fetchAndActivate().addOnCompleteListener {
    progressBar.visibility = View.GONE
    if(it.isSuccessful) {
        val quotes = parseQuotesJson(remoteConfig.getString("quotes"))
        val isNameRevealed = remoteConfig.getBoolean("is_name_revealed")

        displayQuotesPager(quotes, isNameRevealed)
    }
}

RemoteConfig.fetchAndActivate()에 addOnCompleteListener을 달아서 매개변수 가져오기 및 활성화가 완료된 시점에 콜백이 일어나고 그때 ProgressBar를 보이지 않게 해주었다.

 

 

 

728x90
반응형

'Android > Side Projects' 카테고리의 다른 글

My Alarm 앱 개발하기  (0) 2022.02.09
My Alarm 앱 개발하기  (0) 2022.02.08
오늘의 명언 앱 개발하기  (0) 2022.02.06
푸쉬 알림 수신기 앱 개발하기  (0) 2022.02.05
푸쉬 알림 수신기 앱 개발하기  (0) 2022.02.04