Side Project - Today Famous Saying
화면을 스와이프하며 오늘의 명언들을 볼 수 있는 앱을 구현한 프로젝트
학습 회고
오늘은 오늘의 명언 앱 프로젝트를 마쳤다.
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를 보이지 않게 해주었다.
'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 |