【问题标题】:App is throwing an exception "Not in the main thread" when it's trying to add a marker应用程序在尝试添加标记时抛出异常“不在主线程中”
【发布时间】:2020-04-10 07:57:17
【问题描述】:

首先 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”,因为它还没有得到诊所的数据。我不知道我该怎么办...

【问题讨论】:

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


    【解决方案1】:

    听起来onResult() 是在一些异步工作完成后调用的,而且这项工作是在主/ui 线程以外的某个线程上完成的。标记只能添加到主线程上的地图中,因此您需要找到一种方法在适当的线程上执行代码。

    如果您可以控制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(),那么您可以使用Handler 来获得相同的结果:

    new Handler().post(() -> { /* your code here */ });
    

    【讨论】:

      【解决方案2】:

      使用 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);
               }
            });
         }
      });
      

      【讨论】:

      • 请添加更多解释说明您的解决方案为何有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-17
      • 2017-03-16
      相关资源
      最近更新 更多