Android中Google Maps API的onMapReady方法无法获取经纬度值问题
问题原因分析
你遇到的这个问题核心在于异步操作的执行顺序不确定性:
getJSON()里的AsyncTask是异步执行网络请求的,它会在后台线程拉取数据,只有请求完成后才会在onPostExecute()里给latVal和longVal赋值。- 同时,
mapFragment.getMapAsync(this)也是异步回调机制,Google Maps 需要时间完成初始化,之后才会触发onMapReady()。
通常地图初始化的速度会比网络请求快,所以当 onMapReady() 执行时,网络请求还没结束,latVal 和 longVal 还没被赋值,自然是空的;而 onPostExecute() 里能拿到值,是因为此时网络请求已经完成了。
另外注意你原代码里的变量赋值搞反了:longVal = jsonObject.getString("lat");、latVal = jsonObject.getString("lng");,这会导致纬度和经度颠倒,记得修正!
解决方案
这里给你两种最直接的修复方案,按需选择:
方案一:等地图初始化完成后再发起网络请求
这种方法能确保网络请求返回数据时,地图已经准备就绪,可以直接更新:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_child_tracker_page); // 先初始化地图,不着急发网络请求 SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // 地图准备好了,现在发起网络请求拿坐标 getJSON("http://webgax.com/schoolapp/fetch.php"); } // 修改getJSON里的onPostExecute,拿到数据后直接更新地图 private void getJSON(final String urlWebService) { class GetJSON extends AsyncTask<String, Void, String> { @Override public void onPreExecute() { super.onPreExecute(); } @Override public void onPostExecute(String s) { super.onPostExecute(s); try { JSONObject jsonObject = new JSONObject(s); // 修正变量赋值顺序 latVal = jsonObject.getString("lat"); longVal = jsonObject.getString("lng"); // 地图已准备好,直接更新 if (mMap != null) { latNum = Double.parseDouble(latVal); longNum = Double.parseDouble(longVal); LatLng addr = new LatLng(latNum, longNum); float zoomLevel = 16; mMap.addMarker(new MarkerOptions().position(addr).title("WebGax")); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(addr, zoomLevel)); Toast.makeText(getApplicationContext(), "坐标已加载", Toast.LENGTH_LONG).show(); } } catch (Exception e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "解析数据出错", Toast.LENGTH_SHORT).show(); } } @Override public String doInBackground(String... strings) { HashMap<String,String> hashMap=new HashMap<>(); return myCon.postRequest(hashMap, "http://webgax.com/schoolapp/fetch.php"); } } GetJSON getJSON = new GetJSON(); getJSON.execute(); }
方案二:网络请求完成后检查地图状态
如果不想调整请求顺序,可以在 onPostExecute() 里判断地图是否初始化完成,已完成则直接更新,未完成则保存数据,等地图 ready 后再更新:
// 新增标记变量,记录是否已拿到坐标 private boolean hasGotLocation = false; @Override public void onPostExecute(String s) { super.onPostExecute(s); try { JSONObject jsonObject = new JSONObject(s); latVal = jsonObject.getString("lat"); longVal = jsonObject.getString("lng"); hasGotLocation = true; // 检查地图是否已初始化 if (mMap != null) { updateMapWithLocation(); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // 如果已经拿到坐标,直接更新地图 if (hasGotLocation) { updateMapWithLocation(); } else { // 先显示默认标记,等数据加载后替换 LatLng defaultAddr = new LatLng(22, 88); float zoomLevel = 16; mMap.addMarker(new MarkerOptions().position(defaultAddr).title("加载中...")); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultAddr, zoomLevel)); } } // 抽取出更新地图的方法,复用代码 private void updateMapWithLocation() { latNum = Double.parseDouble(latVal); longNum = Double.parseDouble(longVal); LatLng addr = new LatLng(latNum, longNum); float zoomLevel = 16; // 清除默认标记(如果有的话) mMap.clear(); mMap.addMarker(new MarkerOptions().position(addr).title("WebGax")); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(addr, zoomLevel)); }
额外提示
AsyncTask 在 Android API 30 之后已被标记为废弃,如果你开发的是新版本应用,建议使用**协程(Coroutines)**或者 OkHttp + ViewModel + LiveData 的组合处理网络请求,代码会更简洁且符合现代 Android 开发规范。
内容的提问来源于stack exchange,提问作者benid
相关产品推荐
相关产品推荐

