Android中Retrofit2 enqueue的onResponse晚于return执行问题求助
问题根源分析
你遇到的是典型的异步请求执行顺序问题:Retrofit的enqueue()是异步发起网络请求的,它会把请求放到后台线程处理,主线程不会等待请求完成,会直接执行后续的return listTokens代码。这时候onResponse还没被调用,listTokens自然是空的。Thread.sleep()没用是因为它只会阻塞主线程,既没法让异步请求提前完成,还可能引发ANR(应用无响应)。
解决方案
方案1:自定义回调接口(最直接的改造方式)
不让getTokens()直接返回列表,而是定义回调接口,在onResponse中通过回调传递数据。
- 定义回调接口
public interface TokenCallback { void onSuccess(ArrayList<Tokens> tokensList); void onFailure(String errorMessage); }
- 修改
HelperTokens的getTokens()方法
public void getTokens(TokenCallback callback) { ArrayList<Tokens> listTokens = new ArrayList<>(); Retrofit myRetro = APIService.getInstancia(); TokensService myTokensService = myRetro.create(TokensService.class); myTokensService.getAllTokens().enqueue(new Callback<Object>() { @Override public void onResponse(Call<Object> call, Response<Object> response) { if (response.isSuccessful() && response.body() != null) { Map<String, Map> datos = (Map<String, Map>) response.body(); for (Map.Entry<String, Map> item : datos.entrySet()){ Tokens eachToken = new Tokens(); eachToken.setTheToken((String) item.getValue().get("theToken")); eachToken.setfCreacion((String) item.getValue().get("fCreacion")); eachToken.setLimited((double) item.getValue().get("isLimited")); eachToken.setfVencimiento((String) item.getValue().get("fVencimiento")); listTokens.add(eachToken); } // 请求成功,通过回调返回数据 callback.onSuccess(listTokens); } else { callback.onFailure("请求失败,响应为空"); } } @Override public void onFailure(Call<Object> call, Throwable t) { callback.onFailure(t.getMessage()); } }); }
- 调用方式
helperTokens.getTokens(new TokenCallback() { @Override public void onSuccess(ArrayList<Tokens> tokensList) { // 在这里处理拿到的Token列表,比如更新UI Log.d("拿到的Token列表", tokensList.toString()); } @Override public void onFailure(String errorMessage) { // 处理错误情况 Log.d("请求失败", errorMessage); } });
方案2:使用Kotlin协程(推荐,代码更简洁)
如果项目支持Kotlin,协程可以让异步代码看起来像同步逻辑,避免回调嵌套。
- 修改
TokensService为挂起函数
interface TokensService { @GET("Tokens.json") suspend fun getAllTokens(): Response<Map<String, Map<String, Any>>> @POST("Tokens.json") suspend fun postToken(@Body miToken: Tokens): Response<Any> }
- 改写
getTokens()为挂起函数
suspend fun getTokens(): ArrayList<Tokens> { val listTokens = ArrayList<Tokens>() val myRetro = APIService.getInstancia() val myTokensService = myRetro.create(TokensService::class.java) try { val response = myTokensService.getAllTokens() if (response.isSuccessful && response.body() != null) { val datos = response.body()!! for ((_, value) in datos) { val eachToken = Tokens().apply { theToken = value["theToken"] as String fCreacion = value["fCreacion"] as String limited = value["isLimited"] as Double fVencimiento = value["fVencimiento"] as String } listTokens.add(eachToken) } } } catch (e: Exception) { Log.d("Fallo", e.message.toString()) } return listTokens }
- 调用方式(在协程作用域中执行)
lifecycleScope.launch { // Activity/Fragment中用lifecycleScope,ViewModel中用viewModelScope val tokensList = helperTokens.getTokens() // 处理拿到的Token列表 Log.d("拿到的Token列表", tokensList.toString()) }
方案3:使用LiveData(适合MVVM架构)
如果项目采用MVVM,用LiveData可以自动观察数据变化,更新UI。
- 修改
HelperTokens的getTokens()方法
public LiveData<ArrayList<Tokens>> getTokens() { MutableLiveData<ArrayList<Tokens>> tokensLiveData = new MutableLiveData<>(); ArrayList<Tokens> listTokens = new ArrayList<>(); Retrofit myRetro = APIService.getInstancia(); TokensService myTokensService = myRetro.create(TokensService.class); myTokensService.getAllTokens().enqueue(new Callback<Object>() { @Override public void onResponse(Call<Object> call, Response<Object> response) { if (response.isSuccessful() && response.body() != null) { Map<String, Map> datos = (Map<String, Map>) response.body(); for (Map.Entry<String, Map> item : datos.entrySet()){ Tokens eachToken = new Tokens(); eachToken.setTheToken((String) item.getValue().get("theToken")); eachToken.setfCreacion((String) item.getValue().get("fCreacion")); eachToken.setLimited((double) item.getValue().get("isLimited")); eachToken.setfVencimiento((String) item.getValue().get("fVencimiento")); listTokens.add(eachToken); } tokensLiveData.setValue(listTokens); } else { tokensLiveData.setValue(null); } } @Override public void onFailure(Call<Object> call, Throwable t) { tokensLiveData.setValue(null); Log.d("Fallo", t.getMessage()); } }); return tokensLiveData; }
- 调用方式(观察LiveData)
helperTokens.getTokens().observe(this, new Observer<ArrayList<Tokens>>() { @Override public void onChanged(ArrayList<Tokens> tokens) { if (tokens != null) { // 处理拿到的Token列表 Log.d("拿到的Token列表", tokens.toString()); } else { // 处理错误情况 } } });
内容的提问来源于stack exchange,提问作者DFDev3
相关产品推荐
相关产品推荐

