应用尝试添加标记时,应用抛出“不在主线程中”异常

时间:2019-12-17 19:06:23

标签: java android google-maps android-studio exception

首先MapFragment下载诊所的数据(名称,描述,地图上的坐标等),然后尝试为其添加标记。当片段尝试尝试时,应用程序会抛出一个异常,即该行不在主线程中。

E/AndroidRuntime: FATAL EXCEPTION: Thread-12
Process: com.happs.medrate, PID: 4332
com.google.maps.api.android.lib6.common.apiexception.c: Not on the main thread
    at com.google.maps.api.android.lib6.common.m.b(:com.google.android.gms.dynamite_mapsdynamite@19831046@19.8.31 (040306-0):22)
    at com.google.maps.api.android.lib6.common.r.a(:com.google.android.gms.dynamite_mapsdynamite@19831046@19.8.31 (040306-0):5)
    at com.google.maps.api.android.lib6.impl.bm.a(:com.google.android.gms.dynamite_mapsdynamite@19831046@19.8.31 (040306-0):60)
    at com.google.android.gms.maps.internal.j.a(:com.google.android.gms.dynamite_mapsdynamite@19831046@19.8.31 (040306-0):308)
    at ck.onTransact(:com.google.android.gms.dynamite_mapsdynamite@19831046@19.8.31 (040306-0):5)
    at android.os.Binder.transact(Binder.java:612)
    at com.google.android.gms.internal.maps.zza.zza(Unknown Source:10)
    at com.google.android.gms.maps.internal.zzg.addMarker(Unknown Source:54)
    at com.google.android.gms.maps.GoogleMap.addMarker(Unknown Source:48)
    at com.happs.medrate.view.main.MapFragment.onResult(MapFragment.java:87)
    at com.happs.medrate.view.main.MapFragment.lambda$zKz5SBiVflok9pIuOSBON5AS6Uk(Unknown Source:0)
    at com.happs.medrate.view.main.-$$Lambda$MapFragment$zKz5SBiVflok9pIuOSBON5AS6Uk.onResult(Unknown Source:4)
    at com.happs.medrate.model.clinicsdata.GetClinicsData$GetDataThread.run(GetClinicsData.java:61)

有代码(仅方法):

//onResult is for GetClinicsData class (it is a Thread class)
private void onResult(Clinic clinic, @Nullable Exception e){
    this.clinic = new Clinic(clinic.getName(), clinic.getAddress(), clinic.getDescription(), clinic.getGeoPoint());
    MarkerOptions markerOptions = new MarkerOptions();
    LatLng coordinates = new LatLng(clinic.getGeoPoint().getLatitude(), clinic.getGeoPoint().getLongitude());
    markerOptions.position(coordinates);
    map.addMarker(markerOptions);
}


@Override
public void onMapReady(GoogleMap googleMap) {
    map = googleMap;
    if (ContextCompat.checkSelfPermission(getActivity(),
            Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {

        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
                Manifest.permission.ACCESS_FINE_LOCATION)) {
        } else {
            // No explanation needed; request the permission
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    } else {
        map.setMyLocationEnabled(true);
        MyLocationListener.setUpLocationListener(getContext(), getActivity());
    }
}

我已经尝试过在onMapReady中创建“添加标记”部分,但是该片段首先使用onMapReady方法准备了地图,然后才下载诊所的数据,因此当尝试添加标记时,它会抛出“ NullPointerException”,因为它尚未获得诊所的数据。我不知道该怎么办...

3 个答案:

答案 0 :(得分:1)

听起来像ds.Absolute_vorticity_isobaric.metpy.time.values是在完成一些异步工作之后被调用的,并且这项工作是在除main / ui线程之外的某些线程上完成的。标记只能添加到主线程上的映射中,因此您需要找到一种在适当的线程上执行代码的方法。

如果您可以控制ds.Absolute_vorticity_isobaric.metpy.vertical.values的调用者,那可能是切换线程的最佳位置:

onResult()

如果不这样做,则可以在onResult()内部进行线程切换:

getActivity().runOnUiThread(this::onResult);

如果出于某种原因不想使用onResult(),则可以使用private void onResult(Clinic clinic, @Nullable Exception e){ this.clinic = new Clinic(clinic.getName(), clinic.getAddress(), clinic.getDescription(), clinic.getGeoPoint()); MarkerOptions markerOptions = new MarkerOptions(); LatLng coordinates = new LatLng(clinic.getGeoPoint().getLatitude(), clinic.getGeoPoint().getLongitude()); markerOptions.position(coordinates); getActivity().runOnUiThread(() -> { map.addMarker(markerOptions); }); } 获得相同的结果:

runOnUiThread()

答案 1 :(得分:0)

onResult()的{​​{1}}方法内的代码在后台线程上执行,然后在该方法内调用

MainFragment

这行代码应从main / UI线程执行,但会在后台线程上执行,这就是您的应用抛出异常的原因。

解决方案1:在主线程上的map.addMarker(markerOptions); 方法内执行代码。

onResult()

解决方案2:仅在主线程上执行代码行// This handler used to send an executable block of code to main thread. private Handler mainHandler = new Handler(Looper.getMainLooper()); private void onResult(final Clinic clinic, @Nullable Exception e) { mainHandler.post(new Runnable() { @Override public void run() { // These lines of code will be executed on main thread. MapFragment.this.clinic = new Clinic(clinic.getName(), clinic.getAddress(), clinic.getDescription(), clinic.getGeoPoint()); MarkerOptions markerOptions = new MarkerOptions(); LatLng coordinates = new LatLng(clinic.getGeoPoint().getLatitude(), clinic.getGeoPoint().getLongitude()); markerOptions.position(coordinates); map.addMarker(markerOptions); } }); }

map.addMarker(markerOptions)

答案 2 :(得分:0)

使用runOnUiThread

runOnUiThread(new Runnable() {
   @Override
   public void run() {
      MapView mMapView = (MapView) dialog.findViewById(R.id.mapView);
      MapsInitializer.initialize(context);
      mMapView.onCreate(dialog.onSaveInstanceState());
      mMapView.onResume();
      mMapView.getMapAsync(new OnMapReadyCallback() {
      @Override
      public void onMapReady(final GoogleMap googleMap) {
            LatLng myLocation=new LatLng(Double.parseDouble(lat), Double.parseDouble(lon));
            googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
            googleMap.addMarker(new MarkerOptions().position(myLocation).title("My location").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
            float zoomLevel = (float) 16.0; //This goes up to 21
            googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myLocation, zoomLevel));  
            googleMap.getUiSettings().setZoomControlsEnabled(true);
         }
      });
   }
});