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

