Task - YunByungKwan/Fundamental GitHub Wiki
- ๊ณผ์ API ๋ ๋ฒจ ๋ฒ์: 21 ~ 29
- MIN SDK: 21
- Target SDK: 29
- [ ๋ฒ์ ๋ช
/ ๋ฒ์ / API๋ ๋ฒจ ]
- ๋กค๋ฆฌํ(๋ฒ์ 5) 21 ~ 22
- ๋ง์๋ฉ๋ก(๋ฒ์ 6) 23
- ๋๊ฐ(๋ฒ์ 7) 24 ~ 25
- ์ค๋ ์ค(๋ฒ์ 8) 26 ~ 27
- ํ์ด(๋ฒ์ 9) 28
- ํธ ์ผ์ดํฌ(๋ฒ์ 10) 29
- ๋ ๋๋ฒจ๋ฒณ ์ผ์ดํฌ(๋ฒ์ 11) 30
๋จผ์ ํฌ๊ฒ data, di, ui, util๋ก ๋๋ฉ๋๋ค.
ํ๋ก์ ํธ ๊ตฌ์กฐ๋ ์๋๋ก์ด๋ ๊ณต์ ์ฑ ์ํคํ
์ฒ๋ฅผ ์ฐธ๊ณ ํ๊ณ
jetpack์ ์๋ ViewModel๊ณผ LiveData, Databinding์ ์ฌ์ฉํด์ ์ค๊ณํ์์ต๋๋ค.
๊ทธ๋์ data๋ฅผ ๋ณด์๋ฉด
entityํด๋์๋ ํ๋ก์ ํธ์ ํ์ํ ๋ฐ์ดํฐ ํด๋์ค๋ค์ด ์๊ณ
remoteํด๋์๋ Retrofit๊ด๋ จ service ์ธํฐํ์ด์ค ํ์ผ๊ณผ remoteDataSource๊ฐ ์์ต๋๋ค.
repositoryํด๋์๋ repository๊ฐ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์์กด์ฑ ์ฃผ์
์ ์ํด์ dagger๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
์์กด์ฑ ์ฃผ์
์ ํ ์ด์ ๋ ์ ๋ ํ
์คํธ๋ฅผ ์ํด์ ๋์
ํ์ต๋๋ค.
๊ทธ๋์ diํด๋์๋ dagger์ ํ์ํ ํ์ผ๋ค์ด ์์ต๋๋ค.
uiํด๋์๋ Activity์ ViewModel์ด ์๊ณ ,
MainActivity Recyclerview์ ์ฌ์ฉ๋๋ ListAdapterํ์ผ๊ณผ BindingAdapterํ์ผ์ด ์์ต๋๋ค.
์ถ๊ฐ์ ์ผ๋ก MainActivity์ ๊ด๋ จ๋ dagger component์ moduleํ์ผ์ด ์์ต๋๋ค.
utilํด๋์๋ dagger ์ ์ฉ์ ์ํด์ applicationํด๋์ค๊ฐ ์๊ณ
์นดํ
๊ณ ๋ฆฌ์ ์ฝ๋๋ฅผ ์ ์ฅํ๋ Categoryํด๋์ค ํ์ผ,
๊ธฐํ ์์๋ค ์ ์ฅํ๋ Constantsํ์ผ,
๊ทธ๋ฆฌ๊ณ ๊ถํ ๊ถ๋ จ๋ objectํ์ผ์ด ์๊ณ
View๊ด๋ จ ํ์ฅํจ์๋ค์ ์ ์ํ ViewExtํ์ผ์ด ์์ต๋๋ค.
์๋ถํฐ ์กฐ๊ธ ์ธ๋ถ์ ์ผ๋ก ๋ง์๋๋ฆฌ์๋ฉด
entity๋ API๊ด๋ จ ํด๋์ค๋ค์ด๊ณ ํ๋ ์ถ๊ฐํ ๊ฒ Coordinate ํด๋์ค์
๋๋ค.
Coordinateํด๋์ค๋ ์นด์นด์ค๋งต์ ์ง๋ ์ค์ฌ ์ขํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด์ ์ ์ํ์ต๋๋ค.
remote๋ ๋คํธ์ํฌ ํต์ ์ retrofit์ ์ฌ์ฉํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋น๋๊ธฐ ํต์ ์ coroutine์ ์ฌ์ฉํ์ต๋๋ค.
๊ทธ๋์ apiํจ์๋ฅผ suspend๋ก ๋ง๋ค์๊ณ remoteDataSource์์ ์ด apiํจ์๋ฅผ ๋ฆฌํดํฉ๋๋ค.
repository์์๋ remoteDataSource ์์กด์ฑ์ ์ฃผ์
๋ฐ์์ remoteDataSource ๊ด๋ จ ํจ์๋ฅผ ๋ฆฌํดํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ Room์ผ๋ก ๋คํธ์ํฌ ์บ์ฑ ์ถ๊ฐํ ๊น ์ ๊น ๊ณ ๋ฏผํ์ง๋ง, ์ธํฐ๋ท์ด ๋๊ฒผ์ ๊ฒฝ์ฐ ์นด์นด์ค ๋งต์ด ์ผ๋จ ๋ณด์ด์ง ์๊ธฐ ๋๋ฌธ์
์บ์ฑ์ ๋ถํ์ํ ๊ฑฐ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์ด์ ๋ณ๋๋ก ์ถ๊ฐํ์ง ์์์ต๋๋ค.
์ด์ ui์ชฝ์ผ๋ก ๋์ด๊ฐ๋ฉด
๋จผ์ ๊ณผ์ ๊ฐ ์ฐ๋ทธ๋ฐ์ค ์ด์ ์ฌ๊ฐ ๋ณด๋ ์ฑ์ด๊ธฐ ๋๋ฌธ์ ์ง๋๊ฐ ์์ผ๋ฉด ํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐ์ด ๋ค์์ต๋๋ค.
๊ทธ๋์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ฅผ ์ ์ ์ ์๊ฒ ๋ชจ์
๋ ์ด์์์ ์ถ๊ฐํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ง๋ ์ฑ์ด๋ค ๋ณด๋ ํ๋ฉด์ ๊ฐ๋ก๋ก ๋๋ ค์
๋ง์ด ๋ณผ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค. ๊ทธ๋์ ํ๋ฉด ํ์ ํด๋ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๊ณ ์๊ธฐ ์ํด์ ViewModel์์
ํ๋ฉด ์ค์ฌ ์ขํ, ๊ฒ์ ์นดํ
๊ณ ๋ฆฌ, ... ๋ฅผ ์ ์ํ์ต๋๋ค.
MainActivity๋ฅผ ๋ณด๋ฉด ํฌ๊ฒ onClickํจ์๋ค, listener, ๋ง์ปค ์ด๋ํฐ๊ฐ ์์ต๋๋ค.
-
ACCESS_FINE_LOCATION
: GPS์ ๋คํธ์ํฌ๋ก ์์น๋ก ๋จ๋ง๊ธฐ ์์น๋ฅผ ์๋ณ -
ACCESS_COARSE_LOCATION
: ๋คํธ์ํฌ๋ฅผ ์ด์ฉํด์ ๋จ๋ง๊ธฐ ์์น๋ฅผ ์๋ณ - ์๋๋ก์ด๋ 10(29)๋ถํฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์น ๊ถํ๊ณผ ํฌ๊ทธ๋ผ์ด๋ ์์น ๊ถํ์ด ๋๋จ
- ํญ์ ํ์ฉ - ๋ฐฑ๊ทธ๋ผ์ด๋, ํฌ๊ทธ๋ผ์ด๋ ์์น๋ฅผ ๋ชจ๋ ํ์ฉํ๋ค๋ ์๋ฏธ
- ์ฑ ์ฌ์ฉ ์ค์๋ง ํ์ฉ - ํฌ๊ทธ๋ผ์ด๋ ์์น ๊ถํ๋ง ํ์ฉํ๋ค๋ ์๋ฏธ
- Android 11(30)
- ์ฑ ์ฌ์ฉ ์ค์๋ง ํ์ฉ
- ์ด๋ฒ๋ง ํ์ฉ
- ๊ฑฐ๋ถ
- ์์น ๊ถํ(ACCESS_FINE_LOCATION)์ ์ ์์ฒญํด์ผ ํ๋์ง?
- ์ํ ๊ถํ์ด๊ธฐ ๋๋ฌธ์
- GPS๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์
- ์์น ์ค์ ์ ํ๋ ์ด์ ?
- ์ง๋์ ํ์ฌ ๋ด ์์น๋ฅผ ํ์ํ๊ธฐ ์ํด..??
- ๊ฒฝ์ฐ์ ์
-
์์น ๊ถํ X(๊ฑฐ๋ถ) / ์์น ์ค์ X
-
์์น ๊ถํ X(๊ฑฐ๋ถ) / ์์น ์ค์ O
-
์์น ๊ถํ O(์น์ธ) / ์์น ์ค์ X
-
์์น ๊ถํ O(์น์ธ) / ์์น ์ค์ O
-
์์น ์ ๋ณด ์ก์ธ์ค ๊ถํ ์ ํ
-
ํฌ๊ทธ๋ผ์ด๋ ์์น
-
๋ฐฑ๊ทธ๋ผ์ด๋ ์์น ์ ์ฒด์ ์ธ ๊ตฌ์กฐ๋ฅผ ๋จผ์ ๋ง์๋๋ฆฌ๊ฒ ์ต๋๋ค.
์ฑ์ ๊ตฌ์กฐ์ ๊ฒฝ์ฐ, ์๋๋ก์ด๋ ๊ถ์ฅ ์ํคํ ์ฒ๋ฅผ ์ฐธ๊ณ ํด์ ๊ตฌ์ฑํ์ต๋๋ค.
๊ทธ๋์ RemoteDataSoure -> Repository -> ViewModel -> Activity ๋ก ๋ง๋ค์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์์กด์ฑ ์ฃผ์ ์๋ Dagger๋ฅผ ์ฌ์ฉํ๊ณ , ๋น๋๊ธฐ ํต์ ์๋ ์ฝ๋ฃจํด์ ์ฌ์ฉํ์ต๋๋ค.
Dagger๋ฅผ ์ฌ์ฉํ ์ด์ ๋
-
Coroutine์ ์ฌ์ฉํ ์ด์ ๋
[ MainActivity ] MainActivity์์ ์ฒ์์ ์ฌ๋ฌ๊ฐ์ง ์ด๊ธฐํ๋ฅผ ์งํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ SDK๋ฒ์ ์ด 23 ์ด์์ผ ๊ฒฝ์ฐ ACCESS_FINE_LOCATION์ ๋ํ ํผ๋ฏธ์ ์ฒดํฌ๋ฅผ ์งํํฉ๋๋ค. ๊ทธ๋์ ์ฒ์์ ๊ถํ์ด ์น์ธ๋๋์ง ์๋๋์ง๋ก ๋๋๊ณ ์. ์น์ธ์ด ์ด๋ฏธ ๋ ๊ฒฝ์ฐ,
- ์ ACCESS_FINE_LOCATION ๊ถํ๋ง ์์ฒญํ๋์ง?
- ๊ฐ์ด๋์ ๋์จ๋๋ก ACCESS_FINE_LOCATION ๊ถํ์ ์์ฒญํ๋ค.
์ฒ์ ์ง์ ์
-
๊ฒ์์ ํ์ง ์์์ ๊ฒฝ์ฐ
-
๊ฒ์์ ํ ๋ฒ ์ด์ ํ ๊ฒฝ์ฐ
[์๊ตฌ ์ฌํญ]
- ์นด์นด์ค ๋งต ์ฐ๋
- ์นดํ ๊ณ ๋ฆฌ(๋ณ์, ์ฝ๊ตญ, ์ฃผ์ ์)์ ๋ฐ๋ผ ๋ฐ์ดํฐ ๊ฒ์
- ์ง๋ ์ฒ์ ์์น๋ ํ์ฌ ์์น๋ก ํ์
- ๋ง์ปค ๋๋ฅผ ๊ฒฝ์ฐ ๋ง์ปค ์์น๋ก ์ง๋ ์ค์ฌ์ด ์ด๋
- ๊ฒ์์ ํ์ง ์์์ ๊ฒฝ์ฐ->
- suspendCoroutine์ฒ๋ผ coroutine์ ์ผ์์ ์งํ๋ค
- ๊ทธ๋ฌ๋ CancellableContunuation์ ์ ๊ณตํ๋ฉด์
- ์ผ์์ ์ง๋ ๋์์ coroutine job์ด ์ทจ์๋๊ฑฐ๋ ์๋ฃ๋ ๋ CancellationException์ ๋์ง๋ค?
- invokeOnCancellation(handler: CompletionHandler): ์ด continuation์ ์ทจ์๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ํธ์ถํ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ค
-
Continuation
: Tํ์ ์ value๋ฅผ ๋ฐํํ๋ ์ค๋จ์ ํ์ continuation(interface)- [ ๋ด๋ถ์ ๊ฐ๊ณ ์๋ ํจ์๋ค ]
- CoroutineContext ๋ณ์
- resumeWith(result: Result): ๋ง์ง๋ง ์ค๋จ์ ์ ๋ฆฌํด๊ฐ์ผ๋ก์ ์ฑ๊ณต ๋๋ ์คํจ ๊ฒฐ๊ณผ๋ฅผ ๋๊ฒจ์ฃผ๋ฉด์ ์ฝ๋ฃจํด ์คํ์ ์ฌ๊ฐํจ
- [ ํ์ฅ ํจ์๋ค ]
- resume(value: T) = resumeWith(Result.success(value))
- resumeWithException(exception: Throwable) = resumeWith(Result.failure(exception))
-
CancellableContinuation
- [ ์ํ ๋ณ์๋ค ]
- isActive
- isCompleted
- isCancelled
- [ ํจ์๋ค ]
- public fun tryResume(value: T, idempotent: Any? = null): Any?
- public fun tryResume(value: T, idempotent: Any?, onCancellation: ((cause: Throwable) -> Unit)?): Any?
- public fun tryResumeWithException(exception: Throwable): Any?
- public fun completeResume(token: Any)
- public fun initCancellability()
- public fun cancel(cause: Throwable? = null): Boolean : continuation์ ์ทจ์ํจ. ์ทจ์๋๋ฉด true๋ฅผ ๋ฐํ
- public fun invokeOnCancellation(handler: CompletionHandler) : ์ด continuation์ ์ทจ์ํ ๋ ๋์์ ํธ์ถํ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋ก
- public fun CoroutineDispatcher.resumeUndispatched(value: T)
- public fun CoroutineDispatcher.resumeUndispatchedWithException(exception: Throwable)
- public fun resume(value: T, onCancellation: ((cause: Throwable) -> Unit)?)
Retrofit์ suspend ํค์๋๋ฅผ ๋ถ์ด๋ฉด ๋ด๋ถ์ ์ผ๋ก euqueue๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ
- onResponse์์ continuation.resume()์ ํธ์ถํจ
- ๊ทธ ์ธ์ ์คํจํ ๊ฒฝ์ฐ continuation.resumeWithException()์ ํธ์ถํจ
- supervisorJob:
- ListAdapter๋ง๊ณ ๊ทธ๋ฅ recyclerview adapter ๊ตฌํ์, ๋ฐ์ดํฐ ๋ณ๊ฒฝํ ๋ notifyDataSetChanged()๋ฅผ ๋ถ๋ฅด๋ฉด ๋ฆฌ์คํธ๋ฅผ ์ ์ฒด ๋ค ๋ฐ๊ฟ์ผ ํ๋ ๋จ์ ์ด ์๋ค
- notifyDataSetChanged()๋ ๋ฆฌ์คํธ๊ฐ ๊น๋นก์ด๋ ๋ฌธ์ ๊ฐ ์๋ค.
- ๊ทธ๋์ android์์ ๋ง๋ diffUtil์ ํ์ฌ ๋ฐ์ดํฐ ๋ฆฌ์คํธ์ ๊ต์ฒด๋ ๋ฆฌ์คํธ๋ฅผ ๋น๊ตํด์ ์ง์ง ๋ฐ๋์ด์ผ ํ ๋ฐ์ดํฐ๋ง ๋ฐ๊ฟ์ค๋ค.
- ๊ทผ๋ฐ ๋ฉ์ธ์ค๋ ๋์์ ์ด๊ฑธ ๋น๊ตํ๋ฉด ๋ธ๋ฝ์ ์ผ๊ธฐํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ํ๋๋ก ํด์ผ ํ๋ค..=> ๊ทธ๋์ AsyncListDiffer๊ฐ์ด ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ง์ํด์ฃผ๋ ํ์ฅ ํด๋์ค๋ ๋์ด
- ๊ทธ๋ฌ๋ ListAdapter๊ฐ ํจ์ฌ ์ฌ์ฉํ๊ธฐ ์ฝ๋ค(๋ด๋ถ์ ์ผ๋ก AsyncListDiffer๋ฅผ ์ฌ์ฉํจ)
- AsyncListDiffer๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋๋ก ๋ฆฌ์คํธ๋ฅผ ๋น๊ตํ๋ค. => newFixedThreadPool(2)๋ฅผ ์ฌ์ฉํ๋ค.
- diffUtil์ ๋ด๋ถ์ ์ผ๋ก diff ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ค.
- ์๊ฐ๋ณต์ก๋: O(N + D^2 + N'^2)
- ๊ณต๊ฐ๋ณต์ก๋: O(N) (N๊ฐ์ ์์ดํ ์ด ์๋ ๊ฒฝ์ฐ)
- ๊ณต๊ฐ์๋ ์ต์ ํ๋์ด ์์ง๋ง ์๊ฐ ๋ณต์ก๋๋ ๊ฝค ๋์ ์๊ณ ๋ฆฌ์ฆ(๊ทธ๋์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ๋๋ ค์ผ ํ๋ค)
-
PlaceListAdapter -> diffUtilCallback ๋ถ๋ถ
companion object { val diffUtilCallback = object: DiffUtil.ItemCallback<Place>() { // oldItem == newItem ==> oldItem.id == newItem.id ๋ก ๋ฐ๊ฟ์ผ ํ ๋ฏ.. override fun areItemsTheSame(oldItem: Place, newItem: Place): Boolean = oldItem == newItem // ์๋ ๋ง์ ์๋๋ฉด equals ์ค๋ฒ๋ผ์ด๋ํด์ ํ๋๊ฐ๋ค ๋น๊ตํ๋๋ก ํ๊ณ equalsํจ์๋ฅผ ์ฐ๋ฉด ๋๋๋ฐ ์ง๊ธ equals๋ฅผ ์ฐ๊ณ ์๊ณ , // data class์ด๋ค ๋ณด๋ ์์์ equals๊ฐ ๋ด๋ถ ํ๋๋ค ๋น๊ตํ๋๋ก ์๋์ผ๋ก ๋ง๋ค์ด์ ธ ์๊ธฐ ๋๋ฌธ override fun areContentsTheSame(oldItem: Place, newItem: Place): Boolean = oldItem == newItem } }
-
ListAdapter์ ์์ดํ ํด๋ฆญ ์ด๋ฒคํธ ๋ฃ์ ๊ฒฝ์ฐ?
ViewHolder ํด๋์ค์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ฉด ๋ ๋ฏinit { itemView.setOnClickListener { val pos = adapterPosition if(pos != RecyclerView.NO_POSITION) { binding.place?.let { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(it.placeUrl)) ContextCompat.startActivity(itemView.context, intent, null) } } } }