Retrofit异步请求后静态变量外部为空问题求助
解决Retrofit异步请求后静态变量为空的问题
Hey there! Let's break down why your Constants.idcategory is empty when you try to use it outside the onResponse method, and how to fix it.
问题根源:异步操作的时序问题
Retrofit的call.enqueue()是异步执行的——这意味着当你调用这个方法时,它会在后台线程发起网络请求,而主线程会继续往下执行后面的代码(也就是你创建AlertDialog的那段)。
所以实际执行顺序是:
- 你发起网络请求
- 主线程立刻执行
String message = String.valueOf(Constants.idcategory.size());并显示AlertDialog,这时候网络请求还没完成,Constants.idcategory自然是空的 - 过了一会儿网络请求成功,
onResponse才被调用,这时候Constants.idcategory才被赋值
解决方案:让代码等待数据加载完成再执行
有几种简单的方式可以解决这个问题,根据你的需求选一种就行:
方案1:把使用变量的代码移到onResponse内部
这是最直接的方式,因为onResponse只有在数据成功返回后才会执行,这时候Constants.idcategory已经被正确赋值了。修改后的代码如下:
private void idCategory(String ip){ Retrofit retrofit = new Retrofit.Builder().baseUrl(getString(R.string.login)).addConverterFactory(GsonConverterFactory.create()).build(); JsonPlaceHolderApi jsonPlaceHolderApi = retrofit.create(JsonPlaceHolderApi.class); Call<List<ListeCategories>> call = jsonPlaceHolderApi.getIdCategory(ip); call.enqueue(new Callback<List<ListeCategories>>() { @Override public void onResponse(Call<List<ListeCategories>> call, Response<List<ListeCategories>> response) { final List<ListeCategories> chaines = response.body(); for(ListeCategories chaine:chaines){ mots = chaine.getLiveTV().split(","); for (int i = 0; i < mots.length; i++) { Constants.idcategory.add(Integer.parseInt(mots[i])); } break; } // 把AlertDialog的代码移到这里,确保数据已经加载完成 String message = String.valueOf(Constants.idcategory.size()); AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setMessage(message) .setCancelable(false) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { //do things } }); AlertDialog alert = builder.create(); alert.show(); } @Override public void onFailure(Call<List<ListeCategories>> call, Throwable t) { // 别忘了处理请求失败的情况,比如显示错误提示 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setMessage("Failed to load data!") .setCancelable(false) .setPositiveButton("OK", null); AlertDialog alert = builder.create(); alert.show(); } }); }
方案2:用回调接口通知数据加载完成
如果你需要在idCategory方法外部使用Constants.idcategory,可以定义一个回调接口,在onResponse里触发回调,让外部代码知道数据已经准备好:
// 定义回调接口 interface OnCategoryLoadedListener { void onCategoryLoaded(); void onCategoryLoadFailed(); } // 修改方法,添加回调参数 private void idCategory(String ip, final OnCategoryLoadedListener listener){ Retrofit retrofit = new Retrofit.Builder().baseUrl(getString(R.string.login)).addConverterFactory(GsonConverterFactory.create()).build(); JsonPlaceHolderApi jsonPlaceHolderApi = retrofit.create(JsonPlaceHolderApi.class); Call<List<ListeCategories>> call = jsonPlaceHolderApi.getIdCategory(ip); call.enqueue(new Callback<List<ListeCategories>>() { @Override public void onResponse(Call<List<ListeCategories>> call, Response<List<ListeCategories>> response) { final List<ListeCategories> chaines = response.body(); for(ListeCategories chaine:chaines){ mots = chaine.getLiveTV().split(","); for (int i = 0; i < mots.length; i++) { Constants.idcategory.add(Integer.parseInt(mots[i])); } break; } // 触发成功回调 listener.onCategoryLoaded(); } @Override public void onFailure(Call<List<ListeCategories>> call, Throwable t) { // 触发失败回调 listener.onCategoryLoadFailed(); } }); } // 调用方法时使用回调 idCategory(ip, new OnCategoryLoadedListener() { @Override public void onCategoryLoaded() { // 这里可以安全使用Constants.idcategory了 String message = String.valueOf(Constants.idcategory.size()); AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setMessage(message) .setCancelable(false) .setPositiveButton("OK", null); AlertDialog alert = builder.create(); alert.show(); } @Override public void onCategoryLoadFailed() { // 处理失败情况 } });
小提醒:关于静态变量的注意事项
虽然用静态变量Constants.idcategory可以共享数据,但要注意:
- 静态变量会一直存在于内存中,直到App进程被杀,可能造成内存泄漏(如果里面持有Context等对象)
- 多次调用
idCategory方法时,要记得先清空Constants.idcategory,避免数据重复添加
内容的提问来源于stack exchange,提问作者Mahdy Kouka
相关产品推荐
相关产品推荐

