Android 为什么在Jetpack Compose中多次调用此函数?

Android 为什么在Jetpack Compose中多次调用此函数?,android,kotlin,android-jetpack,android-jetpack-compose,Android,Kotlin,Android Jetpack,Android Jetpack Compose,我目前正在试用Android Compose。我有一段文字显示了加密硬币的价格。如果价格上涨,文本的颜色应为绿色,但如果价格下跌,文本的颜色应为红色。当用户单击按钮时调用该函数。问题是函数showPrice()被调用多次(有时只调用一次,有时调用2-4次)。正因为如此,用户可以看到错误的颜色。我能做些什么来确保只调用一次 main活动: @Composable fun MainScreen() { val priceLiveData by viewModel.trackLiveData.

我目前正在试用Android Compose。我有一段文字显示了加密硬币的价格。如果价格上涨,文本的颜色应为绿色,但如果价格下跌,文本的颜色应为红色。当用户单击按钮时调用该函数。问题是函数
showPrice()
被调用多次(有时只调用一次,有时调用2-4次)。正因为如此,用户可以看到错误的颜色。我能做些什么来确保只调用一次

main活动:

@Composable
fun MainScreen() {
    val priceLiveData by viewModel.trackLiveData.observeAsState()
    val price = priceLiveData ?: return

    when (price) {
                is ViewState.Response -> showPrice(price = price.data)
                is ViewState.Error -> showError(price.text)
            }

    Button(onClick = {viewModel.post()} )
}

@Composable
private fun showPrice(price: Double) {
    lastPrice = sharedPref.getFloat("eth", 0f).toDouble()
    val color by animateColorAsState(if (price >= (lastPrice)) Color.Green else 
Color.Red)
    Log.v("TAG", "last=$lastPrice new = $price")
    editor.putFloat("eth", price.toFloat()).apply()
    Text(
          text = price.toString(),
          color = color,
          fontSize = 28.sp,
          fontFamily = fontFamily,
          fontWeight = FontWeight.Bold
      )
 }
  @HiltViewModel
  class MyViewModel @Inject constructor(
    private val repository: Repository
): ViewModel() {

   private val _trackLiveData: MutableLiveData<ViewState<Double>> = MutableLiveData()
   val trackLiveData: LiveData<ViewState<Double>>
       get() = _trackLiveData

   fun post(
   ) = viewModelScope.launch(Dispatchers.Default) {
       try {
           val response = repository.post()
           _trackLiveData.postValue(ViewState.Response(response.rate.round(7)))
       } catch (e: Exception) {
           _trackLiveData.postValue(ViewState.Error())
           Log.v("TAG: viewmodelPost", e.message.toString())
    }
  }
}
sealed class ViewState<out T : Any> {
    class Response<out T : Any>(val data: T): ViewState<T>()
    class Error(val text:String = "Unknown error"): ViewState<Nothing>()
}
视图模型:

@Composable
fun MainScreen() {
    val priceLiveData by viewModel.trackLiveData.observeAsState()
    val price = priceLiveData ?: return

    when (price) {
                is ViewState.Response -> showPrice(price = price.data)
                is ViewState.Error -> showError(price.text)
            }

    Button(onClick = {viewModel.post()} )
}

@Composable
private fun showPrice(price: Double) {
    lastPrice = sharedPref.getFloat("eth", 0f).toDouble()
    val color by animateColorAsState(if (price >= (lastPrice)) Color.Green else 
Color.Red)
    Log.v("TAG", "last=$lastPrice new = $price")
    editor.putFloat("eth", price.toFloat()).apply()
    Text(
          text = price.toString(),
          color = color,
          fontSize = 28.sp,
          fontFamily = fontFamily,
          fontWeight = FontWeight.Bold
      )
 }
  @HiltViewModel
  class MyViewModel @Inject constructor(
    private val repository: Repository
): ViewModel() {

   private val _trackLiveData: MutableLiveData<ViewState<Double>> = MutableLiveData()
   val trackLiveData: LiveData<ViewState<Double>>
       get() = _trackLiveData

   fun post(
   ) = viewModelScope.launch(Dispatchers.Default) {
       try {
           val response = repository.post()
           _trackLiveData.postValue(ViewState.Response(response.rate.round(7)))
       } catch (e: Exception) {
           _trackLiveData.postValue(ViewState.Error())
           Log.v("TAG: viewmodelPost", e.message.toString())
    }
  }
}
sealed class ViewState<out T : Any> {
    class Response<out T : Any>(val data: T): ViewState<T>()
    class Error(val text:String = "Unknown error"): ViewState<Nothing>()
}
我能做些什么来确保只调用一次

没什么,这就是它的工作原理。在视图系统中,您不会问“为什么我的视图无效3次?”。框架会根据需要使视图无效(重新组合),您不需要知道或关心何时会发生这种情况

代码的问题在于,您的Composable正在从首选项中读取旧值,这不是它应该如何工作的,该值应该由viewmodel作为状态的一部分提供。与其只提供新的价格,不如公开一个既有新价格又有旧价格的数据类,然后在composable中使用这两个值来确定要显示的颜色,或者公开价格和要使用的颜色