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

Android Retrofit+MVVM架构下call.enqueue未执行问题求助

Hey there! Let's break down why your Retrofit call.enqueue() isn't executing in your MVVM setup—especially since it works perfectly in a plain Activity. I’ve run into this exact issue a handful of times, so here are the most common fixes and things to check:

1. Double-Check How You’re Instantiating Your ViewModel

If you’re directly creating a ViewModel instance with new (or YourViewModel() in Kotlin), it won’t be tied to your Fragment’s lifecycle. This means the ViewModel (and its Repository calls) could get garbage collected before the Retrofit callback fires.

Do this instead:

// Correct way (uses ViewModelProvider to bind to Fragment lifecycle)
val viewModel = ViewModelProvider(this)[YourViewModel::class.java]

// Wrong way (no lifecycle binding—avoid this!)
val viewModel = YourViewModel()

2. Make Sure Your Retrofit Call Isn’t Getting Garbage Collected

If your Call<Example> object is a local variable inside your Repository’s fetch method, it might be destroyed before the async callback runs. Store it as a member variable in your Repository to keep it alive:

class ExampleRepository {
    // Hold the call as a member variable to prevent GC
    private var currentFetchCall: Call<Example>? = null

    fun fetchExampleData(): LiveData<Result<Example>> {
        val resultLiveData = MutableLiveData<Result<Example>>()
        
        currentFetchCall = RetrofitClient.apiService.getExampleData()
        currentFetchCall?.enqueue(object : Callback<Example> {
            override fun onResponse(call: Call<Example>, response: Response<Example>) {
                Log.d("Retrofit", "Got response!")
                resultLiveData.value = if (response.isSuccessful) {
                    Result.Success(response.body())
                } else {
                    Result.Error("Request failed: ${response.message()}")
                }
            }

            override fun onFailure(call: Call<Example>, t: Throwable) {
                Log.e("Retrofit", "Request failed", t)
                resultLiveData.value = Result.Error(t.message ?: "Unknown error")
            }
        })

        return resultLiveData
    }

    // Add a method to cancel the call when the ViewModel is destroyed
    fun cancelActiveCall() {
        currentFetchCall?.cancel()
    }
}

3. Verify Your LiveData Observer Is Set Up Correctly

Even if the request runs, you won’t see logs if you’re not observing the LiveData properly. Always use viewLifecycleOwner in your Fragment to bind the observer to the Fragment’s view lifecycle (this also prevents memory leaks):

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    // Observe the LiveData with viewLifecycleOwner
    viewModel.exampleData.observe(viewLifecycleOwner) { result ->
        when (result) {
            is Result.Success -> Log.d("Fragment", "Data received: ${result.data}")
            is Result.Error -> Log.e("Fragment", "Error: ${result.message}")
        }
    }

    // Trigger the request after setting up the observer
    viewModel.fetchExampleData()
}

4. Add an OkHttp Logging Interceptor to Debug Requests

To confirm if the request is even being sent, add OkHttp’s logging interceptor to your Retrofit client. This will show you detailed logs of the request and response in Logcat:

// Create the logging interceptor
val loggingInterceptor = HttpLoggingInterceptor().apply {
    level = HttpLoggingInterceptor.Level.BODY // Logs full request/response details
}

// Build OkHttpClient with the interceptor
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

// Initialize Retrofit with the configured client
val retrofit = Retrofit.Builder()
    .baseUrl("YOUR_VALID_BASE_URL")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

Check Logcat for entries starting with OkHttp—if you don’t see any, the request isn’t being dispatched at all.

5. Switch to Coroutines (A More Reliable MVVM Approach)

Retrofit’s callback system is prone to lifecycle issues. Using coroutines with viewModelScope is the modern, recommended way to handle async requests in MVVM:

Repository (with suspend function):

class ExampleRepository {
    private val apiService = RetrofitClient.apiService

    suspend fun fetchExampleData(): Result<Example> {
        return try {
            val response = apiService.getExampleData()
            if (response.isSuccessful) {
                Result.Success(response.body())
            } else {
                Result.Error("Request failed: ${response.message()}")
            }
        } catch (e: Exception) {
            Result.Error(e.message ?: "Unknown error")
        }
    }
}

ViewModel (using viewModelScope):

class ExampleViewModel(private val repository: ExampleRepository) : ViewModel() {
    private val _exampleData = MutableLiveData<Result<Example>>()
    val exampleData: LiveData<Result<Example>> = _exampleData

    fun fetchExampleData() {
        viewModelScope.launch {
            val result = repository.fetchExampleData()
            _exampleData.postValue(result)
        }
    }
}

This approach automatically handles lifecycle cancellation and avoids callback-related garbage collection issues.

6. Rule Out Main Thread Blocking

If your main thread is blocked by a long-running operation (like heavy UI work or a synchronous network call), Retrofit’s UI-thread callback won’t execute. Make sure all blocking operations are moved to background threads.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:27:38