为什么Retrofit的onResponse最后执行?Android MVVM项目该如何修复?
问题原因
- 你调用的Retrofit
enqueue()方法属于异步非阻塞请求:发起请求后直接在当前线程返回,网络请求、响应解析逻辑会在后台子线程执行,直到请求完成才会切回主线程触发onResponse/onFailure回调。主线程的代码执行优先级远高于后台异步回调,所以你在onCreate里主动拿数据时,网络请求还没完成,自然只能拿到初始化的空对象。 - 你的LiveData没有更新逻辑:你在
onResponse里只修改了opw成员变量的指向,没有调用LiveData的setValue()/postValue()方法通知数据更新,就算请求完成,外部观察者也拿不到最新的天气数据。
修复步骤
1. 修改OpenWeatherRepos.java
把需要更新的MutableLiveData传入请求方法,请求完成后主动更新LiveData值:
public class OpenWeatherRepos { private final String TAG = "OpenWeatherRepository"; private final static String BASE_URL = "https://api.openweathermap.org/data/2.5/"; private static OpenWeatherRepos instance; private Retrofit retrofit; private OpenWeatherAPI opwAPI; public static OpenWeatherRepos getInStance() { if(instance == null){ instance = new OpenWeatherRepos(); } return instance; } public MutableLiveData<OpenWeather> getWeather() { retrofit = new RetrofitService().getRetroInstance(BASE_URL); opwAPI = retrofit.create(OpenWeatherAPI.class); MutableLiveData<OpenWeather> data = new MutableLiveData<OpenWeather>(); // 把LiveData传入请求方法 callWeatherAPI(data); return data; } private void callWeatherAPI(MutableLiveData<OpenWeather> data) { Call<OpenWeather> call = opwAPI.getWeather("seoul","this is my id","kr"); call.enqueue(new Callback<OpenWeather>() { @Override public void onResponse(Call<OpenWeather> call, Response<OpenWeather> response) { if(response.isSuccessful() && response.body() != null){ // 请求成功后更新LiveData,postValue可兼容子线程调用场景 data.postValue(response.body()); Log.i(TAG,"API CONNECT SUCCESS"); } } @Override public void onFailure(Call<OpenWeather> call, Throwable t) { Log.d(TAG,"onFailure : "+t.getMessage()); // 失败场景也可以给LiveData传空值或者错误状态,上层做兼容 data.postValue(null); } }); } }
2. 修改MainActivity.java
不要主动调用getValue()拿数据,改为观察LiveData的更新通知,数据就绪后再做后续操作:
public class MainActivity extends AppCompatActivity { private MainActivityViewModel mavm; private final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mavm = new ViewModelProvider(this).get(MainActivityViewModel.class); mavm.init(); Log.i(TAG,"开始发起天气请求"); // 观察LiveData数据更新,数据就绪后自动触发回调 mavm.getWeather().observe(this, openWeather -> { if(openWeather != null){ Log.i(TAG,"拿到天气数据:" + openWeather.toString()); // 此处做更新UI等后续操作 } else { Log.e(TAG,"天气请求失败"); } }); } }
修复后执行逻辑
- Activity onCreate 初始化ViewModel并调用init发起请求,同时注册LiveData观察者
- 后台线程执行网络请求,主线程继续执行后续渲染逻辑
- 网络请求完成后,Repository更新LiveData的值
- LiveData自动通知观察者,Activity回调中拿到最新的天气数据做处理
内容的提问来源于stack exchange,提问作者codingRookie
相关产品推荐
相关产品推荐

