You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android异步读取JSON并渲染地图标记时应用崩溃问题

解决你的AsyncTask+GoogleMap崩溃问题

嘿,我仔细看了你的代码,发现崩溃的核心原因有两个,咱们一步步解决:

问题根源

1. AsyncTask根本没启动

你在onMapReady里创建了FetchJSON实例,但忘了调用execute()方法!这就导致后台下载JSON的逻辑完全没执行,lat和lng始终是空字符串,转成Double的时候肯定会抛出NumberFormatException,直接崩溃。

2. 异步时序错误

就算你调用了execute(),AsyncTask是在后台线程跑的,你立刻调用f.getLat()的时候,后台任务还没完成,lat和lng还是初始的空值,同样会触发转换异常。


修复方案

我们需要让AsyncTask完成JSON下载和解析后,再在主线程里操作GoogleMap添加标记。这里用回调接口的方式,既保证异步逻辑的时序正确,又能避免内存泄漏问题。

步骤1:重构FetchJSON类,添加回调机制

public class FetchJSON extends AsyncTask<Void, Void, List<LocationData>> {
    // 定义回调接口,通知主Activity任务结果
    public interface OnJsonFetchListener {
        void onJsonFetched(List<LocationData> locationList);
        void onFetchFailed(Exception e);
    }

    // 用弱引用持有回调,避免Activity内存泄漏
    private WeakReference<OnJsonFetchListener> mListenerRef;

    public FetchJSON(OnJsonFetchListener listener) {
        mListenerRef = new WeakReference<>(listener);
    }

    // 封装解析后的位置数据
    public static class LocationData {
        public String id;
        public String name;
        public String address;
        public double lat;
        public double lng;
        public String type;

        public LocationData(String id, String name, String address, double lat, double lng, String type) {
            this.id = id;
            this.name = name;
            this.address = address;
            this.lat = lat;
            this.lng = lng;
            this.type = type;
        }
    }

    @Override
    protected List<LocationData> doInBackground(Void... voids) {
        List<LocationData> locationList = new ArrayList<>();
        try {
            URL url = new URL("https://api.myjson.com/bins/ehzqu");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("GET");
            
            InputStream inputStream = httpURLConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String line;
            
            // 用StringBuilder高效拼接JSON数据
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }
            String data = sb.toString();

            JSONArray JA = new JSONArray(data);
            for (int i = 0; i < JA.length(); i++) {
                JSONObject JO = JA.getJSONObject(i);
                String id = JO.getString("id");
                String name = JO.getString("name");
                String address = JO.getString("address");
                // 直接解析为double,避免字符串转换异常
                double lat = JO.getDouble("lat");
                double lng = JO.getDouble("lng");
                String type = JO.getString("type");

                locationList.add(new LocationData(id, name, address, lat, lng, type));
                Log.i("JSON Values", lat + " " + lng);
            }
            return locationList;
        } catch (Exception e) {
            e.printStackTrace();
            // 通知主Activity下载失败
            if (mListenerRef.get() != null) {
                mListenerRef.get().onFetchFailed(e);
            }
            return null;
        }
    }

    @Override
    protected void onPostExecute(List<LocationData> locationList) {
        super.onPostExecute(locationList);
        OnJsonFetchListener listener = mListenerRef.get();
        // 任务完成后通知主Activity处理数据
        if (listener != null && locationList != null) {
            listener.onJsonFetched(locationList);
        }
    }
}

步骤2:修改TrackDifferentLocation类,实现回调并更新地图

public class TrackDifferentLocation extends AppCompatActivity implements OnMapReadyCallback, FetchJSON.OnJsonFetchListener {
    private GoogleMap mMap;
    public static TextView data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track_different_location);
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map_fragment);
        mapFragment.getMapAsync(this);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        Log.i("", "onMapReady()");
        // 启动AsyncTask,传入回调接口
        new FetchJSON(this).execute();
    }

    // 回调方法:JSON下载完成后添加地图标记
    @Override
    public void onJsonFetched(List<FetchJSON.LocationData> locationList) {
        if (mMap == null || locationList.isEmpty()) return;
        for (FetchJSON.LocationData loc : locationList) {
            LatLng latlng = new LatLng(loc.lat, loc.lng);
            // 给标记添加标题和详情,提升用户体验
            mMap.addMarker(new MarkerOptions()
                    .position(latlng)
                    .title(loc.name)
                    .snippet(loc.address));
            // 自动移动相机到第一个标记的位置
            if (locationList.indexOf(loc) == 0) {
                mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 12));
            }
        }
    }

    // 回调方法:处理下载失败的情况
    @Override
    public void onFetchFailed(Exception e) {
        Toast.makeText(this, "加载位置数据失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    // 原有菜单逻辑保持不变
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            this.finish();
        }
        switch (item.getItemId()) {
            case R.id.mapTypeNone: mMap.setMapType(GoogleMap.MAP_TYPE_NONE); break;
            case R.id.mapTypeNormal: mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); break;
            case R.id.mapTypeTerrain: mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); break;
            case R.id.mapTypeSatellite: mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); break;
            case R.id.mapTypeHybrid: mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); break;
            default: break;
        }
        return super.onOptionsItemSelected(item);
    }
}

额外优化说明

  1. 用StringBuilder拼接JSON数据,比data = data + line更高效,避免频繁创建字符串对象。
  2. 直接用getDouble()解析经纬度,省去字符串转double的步骤,避免格式异常。
  3. 使用WeakReference持有回调接口,防止Activity被销毁后AsyncTask还持有引用导致内存泄漏。
  4. 增加了下载失败的提示,提升用户体验。

内容的提问来源于stack exchange,提问作者JamesDoh96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:13:27