코인 앱 만들기#3
Conversation
preludezdev
left a comment
There was a problem hiding this comment.
안녕하세요 선민님,
부족하지만 열심히 리뷰 해봤습니다.
저도 모르는 부분이 많아 나머지 궁금한점은 스터디 때 같이 얘기해보면 좋을 것 같아요 :D
preludezdev
left a comment
There was a problem hiding this comment.
안녕하세요 선민님
부족하지만... 일단 보면서 바로 보이는 것들만 리뷰 달아보았습니다
나머지는 우석님께 맡길게요.
그럼 내일 뵐게요~~
(내일 코루틴 세미나 기대할게요 :D)
| /** | ||
| * Returns the content, even if it's already been handled. | ||
| */ | ||
| fun peekContent(): T = content | ||
| } No newline at end of file |
There was a problem hiding this comment.
Event 클래스 아래에
/**
* An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
* already been handled.
*
* [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
*/
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let {
onEventUnhandledContent(it)
}
}
}
추가하시면 데이터 옵저빙할 때 getContentIfNotHandled() 안쓰고 더 간편하게 코드 작성하실 수 있을거에요 :)
| package com.study.myapplication.api | ||
|
|
||
| import com.study.myapplication.api.model.BithumbTickerResponse | ||
| import retrofit2.http.GET | ||
|
|
||
| interface BithumbApi { | ||
|
|
||
| @GET("public/ticker/all_krw") | ||
| suspend fun getTickerInfo(): BithumbTickerResponse | ||
| } No newline at end of file |
| package com.study.myapplication.base | ||
|
|
||
| import android.os.Bundle | ||
| import android.widget.Toast | ||
| import androidx.annotation.LayoutRes | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.databinding.DataBindingUtil | ||
| import androidx.databinding.ViewDataBinding | ||
| import androidx.lifecycle.ViewModel | ||
| import com.study.myapplication.BR | ||
|
|
||
|
|
||
| abstract class BaseActivity<B : ViewDataBinding, VM : ViewModel>( |
There was a problem hiding this comment.
마찬가지로 Base 패키지는 프레젠테이션 안으로 넣어주셔도 좋을거 같아요
| package com.study.myapplication.di | ||
|
|
||
| import com.study.myapplication.feature.compare.CompareCoinViewModel | ||
| import org.koin.androidx.viewmodel.dsl.viewModel | ||
| import org.koin.dsl.module | ||
|
|
||
| fun getAppModule() = module { | ||
| viewModel { | ||
| CompareCoinViewModel( | ||
| get(), | ||
| get(), | ||
| get(), | ||
| get() | ||
| ) | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
지금은 레이어 분리를 모듈단위가 아니고 패키지 단위로 하고 있어서 di 가 하나에 다 있는데 공부하는 거니까 패키지로 분리하더라도 di 는 각 레이어 패키지마다 있으면 좋을 것 같습니다
| package com.study.myapplication.ext | ||
|
|
||
| import android.widget.ImageView | ||
| import androidx.databinding.BindingAdapter | ||
| import com.bumptech.glide.Glide | ||
|
|
||
|
|
||
| @BindingAdapter("bind:imageUrl") | ||
| fun ImageView.bindImageUrl(imageUrl: String?) { | ||
| imageUrl?.let { | ||
| Glide.with(this.context) | ||
| .load(it) | ||
| .into(this) | ||
| } | ||
| } No newline at end of file |
| package com.study.myapplication.feature.compare | ||
|
|
||
| import android.os.Bundle | ||
| import androidx.lifecycle.Observer | ||
| import com.study.myapplication.R | ||
| import com.study.myapplication.base.BaseActivity | ||
| import com.study.myapplication.databinding.ActivityCompareCoinBinding | ||
| import org.koin.androidx.viewmodel.ext.android.viewModel | ||
|
|
||
| class CompareCoinActivity : | ||
| BaseActivity<ActivityCompareCoinBinding, CompareCoinViewModel>(R.layout.activity_compare_coin) { |
| package com.study.myapplication.utils | ||
|
|
||
| import kotlin.math.abs | ||
|
|
||
| object StringUtil { | ||
|
|
There was a problem hiding this comment.
모듈단위로 분리했다고 가정하면 유틸을 모아둔 패키지도 각 레이어마다 있게 될거같아요
| package com.study.myapplication.data.source | ||
|
|
||
| import com.study.myapplication.domain.entity.Market | ||
| import com.study.myapplication.domain.entity.Ticker | ||
|
|
||
| interface CoinRepository { | ||
|
|
||
| suspend fun getUpbitMarket(): List<Market> | ||
|
|
||
| suspend fun getUpbitCoin(marketList: List<Market>): Map<String, Ticker> | ||
|
|
||
| suspend fun getBithumbCoin(): Map<String, Ticker> | ||
|
|
||
| suspend fun getCoinOneCoin(): Map<String, Ticker> | ||
|
|
||
| } No newline at end of file |
GongSulMin(공설민) 공간입니다.
| setupKoin( | ||
| this, | ||
| getNetworkModule( | ||
| "https://api.upbit.com", |
There was a problem hiding this comment.
상수나 string resource로 사용하면 좀 더 좋지 않을까요?
| binding.run(action) | ||
| } | ||
|
|
||
| fun toastM(message: String) { |
There was a problem hiding this comment.
| fun toastM(message: String) { | |
| protected fun toastM(message: String) { |
상속하는 activity에서만 접근하는 함수라면 이렇게 제한해주면 좀 더 좋지않을까 생각해봤습니다!
| single(named("upbitApi")) { | ||
| Retrofit.Builder() | ||
| .client(get()) | ||
| .addConverterFactory(get()) | ||
| .baseUrl(upbitUrl) | ||
| .build() | ||
| .create(UpbitApi::class.java) | ||
| } |
There was a problem hiding this comment.
single<UpbitApi> {
Retrofit.Builder()
.client(get())
.addConverterFactory(get())
.baseUrl(upbitUrl)
.build()
.create(UpbitApi::class.java)
}
매번 name으로 접근하는 것 보다는 타입을 지정해서 접근한다면,
get할때 name을 넣어주지 않아도 되도록 만들 수 있지 않을까 생각합니다.
| package com.study.myapplication.feature.compare.model | ||
|
|
||
| data class CompareCoinInfo( | ||
| var coinName: String? = null, |
There was a problem hiding this comment.
| var coinName: String? = null, | |
| val coinName: String = "", |
not null type을 사용하는게 좀 더 좋지 않을까요?
| val upbitTickerList = try { | ||
| upbitTickerList.await() | ||
| } catch (e: Exception) { | ||
| Log.d("CompareCoinViewModel", "${e.message}") | ||
| _isDataLoadingError.value = Event("업비트 데이터 로딩 에러 발생" to true) | ||
| _isDataLoading.value = false | ||
| mapOf<String, Ticker>() | ||
| } |
There was a problem hiding this comment.
Exception에 대한 handling을 try ~ catch 를 통해 viewmodel 에서 보다는 model에서 하고,
결과를 내려받는 것이 역할에 맞는것이 아닐까? 하고 생각해봤습니다.
viewmodel 에서 데이터를 로딩하는 것에 대한 판단을 하고있는 것으로 보여서요
There was a problem hiding this comment.
entity에는 id를 넣어라 UUID.Rand~~ 함수를 하면된다
There was a problem hiding this comment.
이거는 좀 적용하는데 시간이 걸릴 것 같습니다 추후에 적용해서 다시 올리겠습니다
| _coinList.postValue( | ||
| getCompareCoinList( | ||
| upbitTickerList, | ||
| bithumbTickerList, | ||
| coinOneTickerList | ||
| ) | ||
| ) | ||
| _isDataLoading.value = false |
There was a problem hiding this comment.
이부분에서 아래의 _isDataLoading.value 에서는 postValue가 아닌 value를 사용하고 있는데
그렇다면 위의 _coinList도 value로 처리해도 되지않을까요?
wswon
left a comment
There was a problem hiding this comment.
추가된 커밋을 일일히 확인하였는데,
저는 더 리뷰할 부분이 없네요. 고생하셨습니다!! 👍

No description provided.