Android开发:用Observable自动刷新Coingecko API币价数据
基于Kotlin Observable的币种价格自动刷新方案
要实现无需Handler的周期性+数据变化触发刷新,你可以结合Kotlin属性委托Delegates.observable(监听价格变量变更)和协程定时任务(周期性请求API)来完成,以下是具体实现步骤:
1. 定义可观察的价格变量
用Delegates.observable包装currentPrice,变量值变更时自动触发回调,在这里处理UI更新逻辑:
import kotlin.properties.Delegates import androidx.lifecycle.ViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.LiveData class CoinDetailViewModel : ViewModel() { // 可观察的当前价格,初始值设为0.0 var currentPrice: Double by Delegates.observable(0.0) { _, oldVal, newVal -> // 仅当值真正变化时通知UI if (oldVal != newVal) { _priceLiveData.postValue(newVal) } } // 用LiveData桥接UI与数据(MVVM架构下推荐) private val _priceLiveData = MutableLiveData<Double>() val priceLiveData: LiveData<Double> = _priceLiveData }
2. 协程实现周期性API请求
利用ViewModel的viewModelScope(自动绑定生命周期,避免内存泄漏)启动定时任务,每隔5-10秒请求Coingecko API并更新currentPrice:
import kotlinx.coroutines.delay import kotlinx.coroutines.launch class CoinDetailViewModel : ViewModel() { // ...上述变量定义... // 启动价格刷新任务,传入币种ID fun startPriceRefresh(coinId: String) { viewModelScope.launch { // 每8秒刷新一次(可在5000-10000毫秒间调整) while (true) { fetchCoinPrice(coinId)?.let { newPrice -> currentPrice = newPrice } delay(8000) } } } // 调用Coingecko API获取价格的实际逻辑 private suspend fun fetchCoinPrice(coinId: String): Double? { // 这里替换为你的API请求实现,比如用Retrofit return try { // 示例:假设API返回包含美元价格的响应 val apiResponse = coingeckoApi.getCoinDetails(coinId) apiResponse.marketData.currentPrice.usd } catch (e: Exception) { e.printStackTrace() null } } }
3. 页面中绑定UI更新
在Activity/Fragment中监听priceLiveData,并启动刷新任务:
import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.observe class CoinDetailActivity : AppCompatActivity() { private lateinit var viewModel: CoinDetailViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_coin_detail) viewModel = ViewModelProvider(this)[CoinDetailViewModel::class.java] // 监听价格变化,更新UI控件 viewModel.priceLiveData.observe(this) { price -> tv_current_price.text = "$${String.format("%.2f", price)}" } // 从Intent获取币种ID(根据你的页面传参逻辑调整) val coinId = intent.getStringExtra("COIN_ID") ?: "" // 启动定时刷新 viewModel.startPriceRefresh(coinId) } }
额外优化建议
- 如果在Activity/Fragment中直接启动协程,推荐用
lifecycleScope.repeatOnLifecycle确保仅在页面处于活跃状态时执行任务:lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { while (true) { // 执行API请求和价格更新 delay(8000) } } } - 已在
Delegates.observable回调中通过oldVal != newVal实现防抖,避免API返回相同价格时重复更新UI。
内容的提问来源于stack exchange,提问作者hgokumus35
相关产品推荐
相关产品推荐

