在 Fragment 上使用 Open Street Map 添加标记

Add marker with Open Street Map on Fragment

我正在尝试将 Open Street 地图与 fragment 一起使用,但是当我调用 "addMarker" 函数时,APP 关闭了。我试图修改功能,但没有成功。我的 objective 是在地图上添加标记。我认为这是因为此函数正在获取 activity 的上下文,但我无法获取片段的上下文。

public class MapFragment extends Fragment implements LocationListener {

private static MapFragment INSTANCE = null;
View view;

MapView map = null;
private MapView osm;
private MapController mc;
private LocationManager locationManager;
private CompassOverlay compassOverlay;
private DirectedLocationOverlay locationOverlay;
private static final int PERMISSAO_REQUERIDA = 1;


public MapFragment() {
    // Required empty public constructor
}

public static MapFragment getINSTANCE(){
    if(INSTANCE==null)
        INSTANCE = new MapFragment();
        return INSTANCE;

}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    view = inflater.inflate(R.layout.fragment_map, container, false);
    //return view;


    if (Build.VERSION.SDK_INT >= M) {
        if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            String[] permissoes = {Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION};
            requestPermissions(permissoes, PERMISSAO_REQUERIDA);
        }
    }
    //onde mostra a imagem do mapa
    Context ctx = getActivity().getApplicationContext();
    Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
    MapView osm = view.findViewById(R.id.map);
    osm.setTileSource(TileSourceFactory.MAPNIK);
    osm.setBuiltInZoomControls(true);
    osm.setMultiTouchControls(true);

    mc = (MapController) osm.getController();
    mc.setZoom(15);


    //GeoPoint center = new GeoPoint(-5.1251,-38.3640);
    //mc.animateTo(center);
    //addMarker(center);

    locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, this);

    /* grade no mapa
    LatLonGridlineOverlay2 overlay = new LatLonGridlineOverlay2();
    osm.getOverlays().add(overlay);
    */

    osm.setMapListener(new MapListener() {
        @Override
        public boolean onScroll(ScrollEvent event) {
            Log.i("Script", "onScroll()");
            return false;
        }

        @Override
        public boolean onZoom(ZoomEvent event) {
            Log.i("Script", "onZoom()");
            return false;
        }
    });


    return view;
}

public void addMarker (GeoPoint center){
    Marker marker = new Marker(osm);
    marker.setPosition(center);
    marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
    marker.setIcon(getResources().getDrawable(R.drawable.fire));
    osm.getOverlays().clear();
    osm.getOverlays().add(marker);
    osm.invalidate();
    marker.setTitle("Sua Localização");
}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSAO_REQUERIDA: {
            // Se a solicitação de permissão foi cancelada o array vem vazio.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permissão cedida, recria a activity para carregar o mapa, só será executado uma vez
                getActivity().recreate();

            }

        }
    }
}

public void onResume() {
    super.onResume();

}


public void onPause(){
    super.onPause();
}

@Override
public void onLocationChanged(Location location) {
    GeoPoint center = new GeoPoint(location.getLatitude(), location.getLongitude());

    mc.animateTo(center);
    addMarker(center);

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}
@Override
public void onDestroy(){
    super.onDestroy();
    if (locationManager != null){
        locationManager.removeUpdates(this);
    }

}

}

Return 这个错误:

Process: ep.tech.myapp, PID: 15419
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context org.osmdroid.views.MapView.getContext()' on a null object reference
    at org.osmdroid.views.overlay.Marker.<init>(Marker.java:93)
    at ep.tech.myapp.Fragments.MapFragment.addMarker(MapFragment.java:132)
    at ep.tech.myapp.Fragments.MapFragment.onLocationChanged(MapFragment.java:175)
    at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:292)
    at android.location.LocationManager$ListenerTransport.-wrap0(Unknown Source:0)
    at android.location.LocationManager$ListenerTransport.handleMessage(LocationManager.java:237)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6543)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:810)

在 onCreateView() 中您缺少 findViewById :

osm= (MapView) view.findViewById(R.id.your_map_id);

我实际上在从 XML 布局加载固定的 OSMDroid MapView 时遇到了问题。它简直要崩溃了。

这是 fragment_test.xml 的样子:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/osm_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.osmdroid.views.MapView
    android:id="@+id/osmap"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

在 Fragment 中加载 MapView 的代码本身,在 onCreateView 中看起来类似:

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Context ctx = getActivity();

    View view = inflater.inflate(R.layout.fragment_test, container, false);

    Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));

    mMapView = view.findViewById(R.id.osmap);
    mMapView.setTileSource(TileSourceFactory.OpenTopo);

但是没有用。我所做的是一种解决方法。我从 XML 中删除了静态 MapView,并在 onCreateView 中动态添加了 MapView。它现在有效。也许这个解决方案对任何人都有帮助?

这是新 fragment_test.xml 的样子(只是空容器):

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/osm_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">

Fragment 中的 onCreateView 是什么样子的(以编程方式将 MapView 添加到空容器):

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Context ctx = getActivity();

    View view = inflater.inflate(R.layout.fragment_test, container, false);

    Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));

    mMapView = new MapView(ctx);
    ((ConstraintLayout) view.findViewById(R.id.osm_fragment)).addView(mMapView);
    mMapView.setTileSource(TileSourceFactory.OpenTopo);