MapView中Retrofit异步加载数据后遍历ArrayList时机错误问题求助
解决异步数据加载导致的Marker遍历空列表问题
这是个非常典型的异步操作时序问题,我来帮你梳理清楚怎么解决~
问题根源
你遇到的核心问题是Retrofit的enqueue()是异步执行的:当你在onMapReady里调用getd("all")后,代码会立刻往下执行遍历mker的循环,但这时候接口请求还在后台网络请求阶段,onResponse回调还没触发,mker里完全没有数据,所以循环自然什么都做不了。
解决方案:把Marker操作移到异步回调里
要确保只有在数据加载完成后,才去遍历列表、创建Marker,我们需要把相关逻辑移到onResponse回调中,同时调整变量的作用域,让各个方法都能访问到mker和map。
步骤1:调整成员变量
先把mker和map定义为类的成员变量,这样在回调里也能访问到:
// 类成员变量:保存Marker数据和地图实例 private ArrayList<MarkerData> mker = new ArrayList<>(); private GoogleMap map;
步骤2:简化onMapReady方法
onMapReady只需要初始化地图并发起数据请求即可:
public void onMapReady(GoogleMap googleMap) { map = googleMap; // 发起异步数据请求 getd("all"); }
步骤3:在onResponse中处理Marker逻辑
修改getd方法的onResponse回调,在数据填充完成后再遍历列表、创建Marker:
private void getd(String selector){ // 可以在这里显示加载对话框(如果需要) // ProgressDialog progress = new ProgressDialog(getActivity()); // progress.setTitle("Charger les infos"); // progress.setMessage("attendre..."); // progress.setProgressStyle(ProgressDialog.STYLE_SPINNER); // progress.show(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(Api.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); Api api = retrofit.create(Api.class); Call<List<col>> call = api.getHeroes(selector); call.enqueue(new Callback<List<col>>() { @Override public void onResponse(Call<List<col>> call, Response<List<col>> response) { // 关闭加载对话框(如果显示了的话) // progress.dismiss(); mker.clear(); // 先清空旧数据,避免重复添加 List<col> colList = response.body(); // 处理空数据情况,避免空指针 if (colList == null) { Log.d("Retrofit", "接口返回数据为空"); return; } // 填充Marker数据并创建地图Marker for (col c: colList){ Log.d("name : ",c.getNom_col()); Log.d("Lat : ",c.getLat_col()); Log.d("Long : ",c.getLong_col()); // ... 其他日志输出 // 添加数据到mker MarkerData markerData = new MarkerData( c.getNom_col(), c.getLat_col(), c.getLong_col(), c.getEmailcol(), c.getType(), c.getDate_creation_col(), c.getCreator() ); mker.add(markerData); // 创建并添加Marker到地图 Marker marker = map.addMarker(new MarkerOptions() .position(new LatLng( Double.parseDouble(c.getLat_col()), Double.parseDouble(c.getLong_col()) )) .title(c.getNom_col()) ); // 可选:把Marker和MarkerData关联,方便后续移除操作 markerData.setMarker(marker); // 需要给MarkerData添加setMarker方法 } // 现在遍历mker是有效的,数据已经全部填充完成 for(int i = 0 ; i < mker.size() ; i++) { Log.d("Date of arrays", mker.get(i).getDate()); } } @Override public void onFailure(Call<List<col>> call, Throwable t) { // 网络请求失败时的处理:关闭对话框、打印错误日志 // progress.dismiss(); Log.e("Retrofit", "请求失败:" + t.getMessage()); } }); }
后续移除Marker的思路
因为mker是类成员变量,你可以随时访问它保存的MarkerData。如果之前把Marker对象关联到了MarkerData里(比如上面的markerData.setMarker(marker)),后续要移除Marker时,只需要遍历mker,调用marker.remove()即可:
// 移除所有Marker的示例 for (MarkerData data : mker) { if (data.getMarker() != null) { data.getMarker().remove(); } } mker.clear();
额外注意事项
- 确保
getLat_col()和getLong_col()返回的字符串可以正确转成double,如果有格式问题需要做异常处理; - 不要忘记实现
onFailure回调,处理网络请求失败的情况; - 如果需要多次请求数据,每次请求前记得清空
mker和地图上的旧Marker,避免重复显示。
内容的提问来源于stack exchange,提问作者bb azeae
相关产品推荐
相关产品推荐

