Подтвердить что ты не робот

Карты Android V2 MapView внутри пользовательского фрагмента (NPE)

Я не хочу использовать или расширять SupportMapFragment или MapFragment. У меня есть собственный базовый класс с кучей кода.

В документации четко указано, что, когда кто-то сам использует MapView, должны быть вызваны все соответствующие методы жизненного цикла (onCreate() onResume() и т.д.).

Большинство методов жизненного цикла в Fragment похожи на Activity, но когда я переключаюсь между моими Fragment, я в конечном итоге получаю обфускацию NPE в методах onDestroy() или onResume().

Все предоставленные образцы используют Activity с MapView, но не пользовательский Fragment.

Кто-то сделал это уже? Можете ли вы предоставить пример кода MapView в своем классе Fragment?

4b9b3361

Ответ 1

Мне удалось включить MapView (v2) в собственный пользовательский фрагмент, встроенный в ViewPager. В моем случае MapView включен в файл макета фрагмента. Мне пришлось вызвать методы жизненного цикла в MapView (onCreate(), называемый onCreateView() из фрагмента) и вызвать вручную MapsInitializer.initialize(context), чтобы избежать NullPointerException из класса BitmapDescriptorFactory (чтобы получить растровое изображение для маркеров). Этот последний трюк странный, и я не знаю, почему система Map неправильно инициализирована без этого вызова, может быть, это просто ошибка в текущей версии...

В моем случае у меня не было NullPointerException в onResume() или onDestroy().

Ответ 2

Я немного боролся с ответом PoPy, но в итоге мне это удалось, и вот что я придумал. Вероятно, это полезно для других, которые также сталкиваются с этой проблемой:

public class MyMapFragment extends Fragment {

    private MapView mMapView;
    private GoogleMap mMap;
    private Bundle mBundle;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View inflatedView = inflater.inflate(R.layout.map_fragment, container, false);

        try {
            MapsInitializer.initialize(getActivity());
        } catch (GooglePlayServicesNotAvailableException e) {
            // TODO handle this situation
        }

        mMapView = (MapView) inflatedView.findViewById(R.id.map);
        mMapView.onCreate(mBundle);
        setUpMapIfNeeded(inflatedView);

        return inflatedView;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBundle = savedInstanceState;
    }

    private void setUpMapIfNeeded(View inflatedView) {
        if (mMap == null) {
            mMap = ((MapView) inflatedView.findViewById(R.id.map)).getMap();
            if (mMap != null) {
                setUpMap();
            }
        }
    }

    private void setUpMap() {
        mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
    }

    @Override
    public void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    public void onDestroy() {
        mMapView.onDestroy();
        super.onDestroy();
    }
}

И вот соответствующий res/layout/map_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.google.android.gms.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

Вы можете опустить RelativeLayout (и переместить объявление xmlns до вашего нового корневого элемента, в этом случае com.google.android.gms.maps.MapView), если в вашем макете есть только один элемент, как в этом примере.

Ответ 3

При использовании отдельного MapView следующие две вещи имеют жизненно важное значение

    //at Activity
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      MapsInitializer.initialize(this);
      mapView.onCreate(savedInstanceState); 
    }
    //or at Fragment
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                       Bundle savedInstanceState) {

       MapsInitializer.initialize(getActivity());  
       mapView.onCreate(mBundle);
     }
    //along with the following
    @Override
    protected void onResume() {
       super.onResume();
       if (mapView != null)
        mapView.onResume();
      }

    @Override
    protected void onDestroy() {
       super.onDestroy();
       if (mapView != null)
        mapView.onDestroy();
    }

    @Override
    public void onLowMemory() {
      super.onLowMemory();
      if (mapView != null)
        mapView.onLowMemory();
    }