Фрагмент Карт Google, возвращающий нуль внутри фрагмента
Итак, у меня есть пустой фрагмент, содержащий фрагмент карты. Всякий раз, когда я пытаюсь активировать фрагмент, содержащий карту, мое приложение падает и возвращает ошибку нулевого указателя в этой строке:
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();
Полное сообщение об ошибке:
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.maps.GoogleMap com.google.android.gms.maps.MapFragment.getMap()' on a null object reference
at com.collusion.serviceassistant.ReturnVisitDetails.onViewCreated(ReturnVisitDetails.java:39)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:904)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
at android.app.BackStackRecord.run(BackStackRecord.java:684)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
Вот мой код фрагмента:
import android.app.Activity;
import android.app.Dialog;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class ReturnVisitDetails extends Fragment {
static final LatLng HAMBURG = new LatLng(53.558, 9.927);
static final LatLng KIEL = new LatLng(53.551, 9.993);
private GoogleMap map;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_return_visit_add, container, false);
return rootView;
}
public void onViewCreated(View view, Bundle savedInstanceState)
{
// Get a handle to the Map Fragment
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();
Marker hamburg = map.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = map.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));
// Move the camera instantly to hamburg with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
}
}
И мой родительский фрагмент XML-макет:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.collusion.serviceassistant.ReturnVisitDetails"
android:background="#009688">
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
</RelativeLayout>
У кого-нибудь есть идея, почему фрагмент карты возвращает null?
EDIT: Теперь у меня есть этот код для инициализации карты:
MapFragment mapFragment = new MapFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.rl_map_container, mapFragment).commit();
map = mapFragment.getMap();
Marker hamburg = map.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = map.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));
// Move the camera instantly to hamburg with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
И он все равно возвращает значение нулевого указателя
Ответы
Ответ 1
Эта проблема произошла со мной, когда я попытался перенести проект Eclipse в проект Android Studio.
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.maps.GoogleMap com.google.android.gms.maps.SupportMapFragment.getMap()' on a null object reference
Я использовал его с помощью функции "Фрагмент":
((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.mapToday)).getMap();
Однако проблема заключалась в том, что раньше я использовал определенную версию Служб Google Play (4.3.23).
Но сборка Gradle выбирает самую последнюю версию (compile 'com.google.android.gms:play-services:+')
Я попробовал другую версию, например (6.1.71). Но все же давал исключение с нулевой точкой.
Я использовал ту же старую версию, что и раньше, и это сработало.
compile 'com.google.android.gms:play-services:4.3.23'
Это работает для меня как временное решение. Однако это будет проблемой, когда мне нужно обновить до
новая библиотека игровых сервисов.
Кажется, что нет конкретной библиотеки карт с этой версией, доступной для Gradle build
когда я пробую вот так:
compile 'com.google.android.gms:play-services-maps:4.3.23'
Ответ 2
Я решил проблему.
эта строка, когда у меня есть viewpager:
mMap = ((SupportMapFragment) MainActivity.fragmentManager
.findFragmentById(R.id.mapView)).getMap();
вы должны изменить на это:
mMap = ((SupportMapFragment) getChildFragmentManager()
.findFragmentById(R.id.mapView)).getMap();
Ответ 3
Ваш класс распространяется от Fragment
, и вы используете объявленный в макете Fragment
, но вложенный фрагмент работает только при динамическом добавлении.
Итак, у вас есть два варианта:
1) Расширение от FragmentAcivity
вместо Fragment
и применение правильных методов.
2) Добавьте Fragment
динамически, как показано ниже:
//ReturnVisitDetails
MapFragment mapFragment = new MapFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.rl_map_container, mapFragment).commit();
//Layout
<FrameLayout
android:id="@+id/rl_map_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- ОБНОВЛЕНО -
Полный пример использования Карт Google внутри Fragment
:
//TestFragmentActivity
public class TestFragmentActivity extends android.support.v4.app.FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_fragment_activity);
}
}
//TestFragment
public class TestFragment extends android.support.v4.app.Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.test_fragment, container, false);
CustomMapFragment mapFragment = new CustomMapFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.map_container, mapFragment).commit();
return rootView;
}
}
//CustomMapFragment
public class CustomMapFragment extends com.google.android.gms.maps.SupportMapFragment {
private final LatLng HAMBURG = new LatLng(53.558, 9.927);
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
GoogleMap googleMap = getMap();
googleMap.addMarker(new MarkerOptions().position(HAMBURG).title("Hamburg"));
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
googleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
}
}
//test_fragment_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/map"
class="your_package.TestFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
//test_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/map_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Ответ 4
Я искал много потоков на этом, поскольку у меня была такая же проблема со старыми сервисами Google Play. Поскольку Виктор сказал, что ваш класс простирается от фрагмента, и он должен использовать другой фрагмент, определенный в макете, наилучшим подходом будет использование getChildFragmentManager()
вместо getSupportFragmentManager()
.
Также getMap() method is deprecated
теперь, как указано в документах google. Пожалуйста, обратитесь к этому дополнительно:
https://developers.google.com/android/reference/com/google/android/gms/maps/MapFragment.html#getMap()
Ниже приведен рабочий код, который я тестировал на разных устройствах старых игровых сервисов. Это приведет к генерации сообщения по умолчанию в случае устройства, имеющего более старые сервисы игры google, и в случае, если объект GoogleMap
возвращает null:
class MyFragment extends Fragment
{
SupportMapFragment myMapFragment;
GoogleMap myMap;
View convertView;
FragmentManager fm;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
convertView=inflater.inflate(R.layout.mymap,null);
fm=getChildFragmentManager();
myMapFragment=(SupportMapFragment) fm.findFragmentById(R.id.myMapId);
// here instead of using getMap(), we are using getMapAsync() which returns a callback and shows map only when it gets ready.
//it automatically checks for null pointer or older play services version, getMap() is deprecated as mentioned in google docs.
myMapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googlemap) {
// TODO Auto-generated method stub
myMap=googlemap;
startMap();
}
});
return convertView;
}
}
Смотрите эту тему для получения дополнительной информации.
Ответ 5
Может ли это быть проблемой перехода на целевую версию sdk из 21? Если это так, вам может быть интересно следующее решение:
MapFragment или MapView getMap() возвращает null на Lollipop
Ответ 6
Попробуйте использовать SupportMapFragment вместо MapFragment. Этот код работает для меня для фрагмента, просто попробовал:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapFragment extends Fragment {
private GoogleMap map;
static final LatLng HAMBURG = new LatLng(53.558, 9.927);
static final LatLng KIEL = new LatLng(53.551, 9.993);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_map, container,
false);
// Get a handle to the Map Fragment
map = ((SupportMapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
Marker hamburg = map.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = map.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));
// Move the camera instantly to hamburg with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
return rootView;
}
}
и ваш макет:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<fragment
android:id="@+id/map"
android:name="com.example.test.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
Ответ 7
Проблема может быть связана с тем, что ваш targetSdkVersion
выше версии используемой библиотеки поддержки Android.
Это было моим делом, в одном из проектов, над которыми мы работали над targetSdkVersion
, было 21, а версия Support Library - 19.0.0. Изменение targetSdkVersion
до 19 устраняет проблему.
Ответ 8
Я могу столкнуться с такой же проблемой, но, наконец, я могу решить эту ошибку. Теперь карта правильно отображается...
= > Вызвать метод initilizeMap() во фрагменте в методе onCreateView()...
= > Объявить глобальную переменную, например,
private GoogleMap googleMap;
private void initilizeMap() {
try {
// Changing marker icon
// marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.my_marker_icon)));
// adding marker
if (googleMap == null) {
googleMap = ((MapFragment)getActivity().getFragmentManager()
.findFragmentById(R.id.map)).getMap();
// create marker
MarkerOptions marker = new MarkerOptions().position(
new LatLng(latitude, longitude)).title(
"YourCare");
// Changing marker icon
MarkerOptions icon = marker.icon(BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_ROSE));
// adding marker
LatLng latLng = new LatLng(latitude, longitude);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(
latLng, 15);
googleMap.animateCamera(cameraUpdate);
// locationManager.removeUpdates(this);
googleMap.addMarker(marker);
googleMap.setMyLocationEnabled(true);
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getActivity(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
}
} catch (Exception e) {
System.out.print("Error :" + e.getMessage());
}
}