Карты Android V2 MapView внутри пользовательского фрагмента (NPE)
Я не хочу использовать или расширять SupportMapFragment
или MapFragment
. У меня есть собственный базовый класс с кучей кода.
В документации четко указано, что, когда кто-то сам использует MapView
, должны быть вызваны все соответствующие методы жизненного цикла (onCreate()
onResume()
и т.д.).
Большинство методов жизненного цикла в Fragment
похожи на Activity
, но когда я переключаюсь между моими Fragment
, я в конечном итоге получаю обфускацию NPE в методах onDestroy()
или onResume()
.
Все предоставленные образцы используют Activity
с MapView
, но не пользовательский Fragment
.
Кто-то сделал это уже? Можете ли вы предоставить пример кода MapView
в своем классе Fragment
?
Ответы
Ответ 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();
}