Android开发:为何要在ViewModel中执行网络请求?配置变化时请求重复问题解惑
Great question! Let's unpack this—first, the extra reasons to put network calls in ViewModel, then why you're still seeing repeated API calls when rotating your device.
Additional Reasons to Run Network Requests in ViewModel
Beyond retaining data across configuration changes, there are several key benefits:
- Separation of concerns: Activities/Fragments should focus solely on UI rendering and user interactions. Shifting network logic (and other business logic) to ViewModel keeps your UI code clean, maintainable, and easier to debug. No more cluttering your Fragment with Retrofit setup or error handling—let the ViewModel handle that heavy lifting.
- Lifecycle safety: ViewModels outlive temporary UI destructions (like rotations) but are cleared when the UI is permanently destroyed (e.g., when the user navigates away). This means you can run network requests without worrying about memory leaks (as long as you use lifecycle-aware scopes like
viewModelScopefor coroutines). - Data sharing across UI components: If multiple Fragments in the same Activity share a ViewModel, you can reuse the network request result across all of them. No need to duplicate API calls for each Fragment—saves bandwidth and keeps data consistent.
- Easier testing: ViewModels don't depend on UI components, so writing unit tests for your network logic is straightforward. You can mock your repository layer and validate how the ViewModel handles success, errors, and loading states without spinning up an Activity or Fragment.
Why Your API Calls Still Repeat on Configuration Changes
Here's the thing: ViewModel doesn't automatically prevent repeated requests out of the box. The issue likely comes from how you're triggering the request. For example:
- If you call the ViewModel's fetch method in your Fragment's
onViewCreated()(or similar lifecycle method), that method runs every time the Fragment is recreated after a rotation—so it re-triggers the request. - If you mistakenly reinitialize the ViewModel logic on Fragment recreation (though ViewModels are supposed to be reused), that could also cause duplicate calls.
Fixes to Stop Repeated Requests
You need to add state tracking in your ViewModel to avoid redundant calls. Here are a few common approaches:
Cache the result and track loading state
Add variables to store the cached result and whether a request is already in progress:private val _data = MutableLiveData<Result<MyData>>() val data: LiveData<Result<MyData>> = _data private var cachedResult: Result<MyData>? = null private var isRequestInProgress = false fun fetchData() { // Return cached result if available cachedResult?.let { _data.value = it return } // Don't start a new request if one is already running if (isRequestInProgress) return isRequestInProgress = true viewModelScope.launch { try { val freshData = repository.fetchMyData() cachedResult = Result.Success(freshData) _data.value = cachedResult } catch (e: Exception) { _data.value = Result.Error(e) } finally { isRequestInProgress = false } } }Now, when your Fragment calls
fetchData()after a rotation, it'll either use the cached result or skip the request if one's already underway.Use Kotlin Flow with
stateIn
If you're using Flow instead of LiveData, convert your request Flow to a StateFlow that retains its state across subscriptions:val data: StateFlow<Result<MyData>> = repository.fetchMyDataFlow() .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), // Keep subscription alive for 5s after UI disconnects initialValue = Result.Loading )The
WhileSubscribed(5000)ensures that if the UI is recreated within 5 seconds (like during a rotation), the Flow doesn't re-execute the network request—it just emits the latest state to the new subscriber.Avoid triggering requests in Fragment lifecycle methods
Instead of callingfetchData()inonViewCreated(), trigger it only when necessary—like when the user taps a button, or when the screen first loads and there's no cached data.
Wrap-Up
ViewModel is an ideal place for network requests thanks to its lifecycle benefits and separation of concerns, but you need to handle request state manually to prevent duplicates on configuration changes. Adding caching or using Flow's state retention will fix the repeated API calls you're seeing.
内容的提问来源于stack exchange,提问作者Sparsh Dutta

