You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MVVM架构下应用从后台切至前台时如何调用API

Android MVVM架构下后台切前台调用API的实现方法

一、依赖准备

确保项目引入Jetpack Lifecycle相关依赖,用于监听应用全局生命周期:

dependencies {
    implementation "androidx.lifecycle:lifecycle-process:2.6.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
    // Retrofit(用于API调用,按需引入)
    implementation "com.squareup.retrofit2:retrofit:2.9.0"
    implementation "com.squareup.retrofit2:converter-gson:2.9.0"
}

二、实现全局前后台状态监听

通过ProcessLifecycleOwner监听应用全局的前后台切换状态,封装成单例管理器:

class AppForegroundStateManager private constructor() : LifecycleObserver {

    private val _isForeground = MutableLiveData<Boolean>()
    val isForeground: LiveData<Boolean> = _isForeground

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onEnterForeground() {
        _isForeground.postValue(true)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onEnterBackground() {
        _isForeground.postValue(false)
    }

    companion object {
        val instance: AppForegroundStateManager by lazy { AppForegroundStateManager() }
    }
}

在自定义Application类中注册该观察者:

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppForegroundStateManager.instance)
    }
}

三、MVVM分层实现API调用

1. Repository层(数据请求)

负责实际的API调用逻辑,与ViewModel解耦:

// Retrofit接口定义
interface ApiService {
    @GET("api/latest-data")
    suspend fun fetchLatestData(): ApiResponse
}

// Repository实现
class DataRepository(private val apiService: ApiService) {
    suspend fun getLatestData(): ApiResponse {
        return apiService.fetchLatestData()
    }
}

2. ViewModel层(业务逻辑处理)

观察前后台状态,在应用切前台时触发API请求,并通过LiveData通知View层:

// 封装API请求状态的密封类
sealed class Resource<out T> {
    object Loading : Resource<Nothing>()
    data class Success<out T>(val data: T) : Resource<T>()
    data class Error(val message: String) : Resource<Nothing>()
}

class MainViewModel(private val repo: DataRepository) : ViewModel() {

    private val _apiResult = MutableLiveData<Resource<ApiResponse>>()
    val apiResult: LiveData<Resource<ApiResponse>> = _apiResult

    private var lastRequestTime = 0L
    private val MIN_REQUEST_INTERVAL = 5 * 60 * 1000 // 5分钟防重复请求

    init {
        observeForegroundState()
    }

    private fun observeForegroundState() {
        AppForegroundStateManager.instance.isForeground.observeForever { isForeground ->
            if (isForeground) {
                val currentTime = System.currentTimeMillis()
                if (currentTime - lastRequestTime > MIN_REQUEST_INTERVAL) {
                    lastRequestTime = currentTime
                    fetchData()
                }
            }
        }
    }

    private fun fetchData() = viewModelScope.launch {
        _apiResult.postValue(Resource.Loading)
        try {
            val data = repo.getLatestData()
            _apiResult.postValue(Resource.Success(data))
        } catch (e: Exception) {
            _apiResult.postValue(Resource.Error(e.message ?: "数据请求失败"))
        }
    }

    override fun onCleared() {
        super.onCleared()
        // 移除观察者,避免内存泄漏
        AppForegroundStateManager.instance.isForeground.removeObserver(::observeForegroundState)
    }
}

3. View层(UI更新)

在Activity/Fragment中观察ViewModel的LiveData,根据请求状态更新UI:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化ViewModel(可通过DI框架注入Repository,示例用默认Provider)
        val apiService = Retrofit.Builder()
            .baseUrl("https://your-api-domain.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
        val repo = DataRepository(apiService)
        viewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                return MainViewModel(repo) as T
            }
        })[MainViewModel::class.java]

        // 观察API请求结果
        viewModel.apiResult.observe(this) { resource ->
            when (resource) {
                Resource.Loading -> showLoadingDialog()
                is Resource.Success -> {
                    dismissLoadingDialog()
                    updateUI(resource.data)
                }
                is Resource.Error -> {
                    dismissLoadingDialog()
                    Toast.makeText(this, resource.message, Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    // 省略UI操作方法
    private fun showLoadingDialog() { /* ... */ }
    private fun dismissLoadingDialog() { /* ... */ }
    private fun updateUI(data: ApiResponse) { /* ... */ }
}

四、关键注意事项

  • 防重复请求:通过时间间隔判断避免短时间内重复调用API,减少服务器压力。
  • 内存泄漏防护:ViewModel中使用observeForever后,必须在onCleared方法中移除观察者。
  • 异常处理:API调用时捕获网络异常、解析异常等,通过Resource.Error状态通知View层。
  • 权限检查:确保应用拥有网络权限,可在请求前添加网络状态判断。

内容的提问来源于stack exchange,提问作者Andyson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:30:44