Google Map Android API v2: GoogleMap имеет значение null

Я пытаюсь изучить использование класса MapView для отображения GoogleMap, но безуспешно, так как в большинстве примеров кода используется MapFragment, который мне не нужен.

Я использую Google Maps Android API v2.

Сначала просто для тестирования с помощью здесь из примера Google мне удалось получить типичная карта нормалей для отображения.

public class POnlineMapView extends Activity {

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.online_map_activity);
    }
}

Приведенный выше код работает отлично, что показывает, что все настроено правильно.

Теперь я пытаюсь использовать класс MapView для управления настройками отображения, такими как центральная точка, но кажется, что я получаю нулевой объект каждый раз, когда пытаюсь получить объект GoogleMap. Почему это так?

public class POnlineMapView extends Activity {

    private MapView myMapView;
    private GoogleMap map;

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

        myMapView = new MapView(getApplicationContext());
        Bundle b = getIntent().getExtras();
        double longitude = b.getDouble("longitude");
        double latitude = b.getDouble("latitude");

        setContentView(R.layout.online_map_activity);
        map = myMapView.getMap();

        CameraUpdate center= CameraUpdateFactory.newLatLng(new LatLng(latitude,longitude));
        CameraUpdate zoom=CameraUpdateFactory.zoomTo(17);

        map.moveCamera(center); //this gives a NullPointerException, probably due to the myMapView.getMap() method?
        map.animateCamera(zoom);    
    }
}

person lyk    schedule 25.01.2013    source источник
comment
даже если вам не нужен фрагмент карты, вам все равно нужна карта...   -  person njzk2    schedule 25.01.2013
comment
Что ты имеешь в виду? Вы имеете в виду, что класс не должен расширяться от Activity?   -  person lyk    schedule 25.01.2013


Ответы (6)


Проверьте, установлены ли (и обновлены) службы Google Play.

См. Google Maps Android API v2 выдает исключение GooglePlayServicesNotAvailableException, устарело, SupportMapFragment .getMap() возвращает null

Также прочитайте https://developers.google.com/maps/documentation/android/map (раздел Проверка доступности карты)

person userM1433372    schedule 25.01.2013

Это кажется старым вопросом, но у меня была такая же проблема, когда я пытался использовать MapView.

Предполагая, что вы правильно импортировали библиотеку Google Play Services, вам нужно проверить, есть ли у вас доступ к Google Services, вы можете сделать это в своем методе onCreate, и вы должны инициализировать Google Maps Android AP. вы можете сделать это, добавив следующий код в свой метод onCreate

try {
        MapsInitializer.initialize(this);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("Address Map", "Could not initialize google play", e);
    }

switch (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) )
{
  case ConnectionResult.SUCCESS:
      Toast.makeText(getApplicationContext(), "SUCCESS", Toast.LENGTH_SHORT).show();
      break;
  case ConnectionResult.SERVICE_MISSING: 
      Toast.makeText(getApplicationContext(), "SERVICE MISSING", Toast.LENGTH_SHORT).show();
      break;
  case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED: 
      Toast.makeText(getApplicationContext(), "UPDATE REQUIRED", Toast.LENGTH_SHORT).show();
      break;
  default: Toast.makeText(getApplicationContext(), GooglePlayServicesUtil.isGooglePlayServicesAvailable(this), Toast.LENGTH_SHORT).show();
}

Если вы получаете УСПЕХ, то пока все работает. Вы также должны реализовать методы жизненного цикла Activity и вызвать соответствующий метод вашего представления карты внутри каждого из этих методов:

@Override
protected void onResume() {
    myMapView.onResume();
    super.onResume();

}

@Override
protected void onPause() {
    myMapView.onResume();
    super.onPause();

}

@Override
protected void onDestroy() {
    myMapView.onDestroy();
    super.onDestroy();
   //((MapView)findViewById(R.id.mapView)).onDestroy();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    myMapView.onLowMemory();
}

Наконец, вы должны убедиться, что вы добавили свой ключ API Карт Google в свой файл манифеста:

<meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value="YOUR KEY"/>

Инструкции по получению ключа можно найти здесь: https://developers.google.com/maps/documentation/android/start#installing_the_google_maps_android_v2_api

Изменить: забыл упомянуть, вам также необходимо установить разрешения приложений в файле манифеста.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Это должно быть установлено внутри блока приложения...

person Eduardo Martinez    schedule 17.10.2013

Спасибо, вы наконец-то дали мне ключ к программной инициализации Карты, как глупо я за этим следил :)

Ну, иногда нет возможности использовать MapFragment (или SupportMapFragment аналогично), т.е. когда вы хотите использовать карту из фрагмента! На самом деле это очень распространенный случай при работе с вкладками (ActionBar), где шаблон заключается в использовании фрагментов. Итак, у вас есть собственный фрагмент для каждой вкладки, и в этом фрагменте для карты вы хотите раздуть макет, который содержит фрагмент для MapFragment, и вуаля — удачи!

Теперь, согласно спецификациям MapView, никоим образом не сказано, что использование MapView не рекомендуется или не рекомендуется, так почему бы мне не использовать его? Я не хотел хаков в поддержке вложенных фрагментов без поддержки со стороны SDK (даже недавняя поддержка lib v13 вроде бы содержит баги и вложенные фрагменты из лейаута не поддерживаются), поэтому использование MapView превратилось для меня в KISS.

Ниже приведен мой CustomMapFragment, который я использую с инфляцией макета (что позволяет создавать сложные макеты) и встроенной картой, вы можете использовать его. Вы также можете расширить фрагмент из библиотеки поддержки, а не из SDK.

Метод onCreateView() раздувает макет (просто укажите свой собственный) и ожидает, что макет будет иметь группу просмотра (relativelayout, linearlayout и т. д.) с идентификатором «mapViewHolder», к которой будет прикреплен mapView при создании макета. Активность должна реализовывать интерфейс CustomMapFragment.Handler, иначе будет выброшено исключение ClassCastException.

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import R;

public class AppMapFragment extends Fragment {
  /*
   * to interact with activity
   */
  public static interface Handler {
    void onMapResume(GoogleMap map);
  }

  private Handler handler;
  private MapView mapView;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
      // initialize explicitely, since we're working with MapView (not MapFragment)
      MapsInitializer.initialize(getActivity());
      this.mapView = new MapView(getActivity());
      this.mapView.onCreate(savedInstanceState);
    } catch (GooglePlayServicesNotAvailableException e) {
      Toast.makeText(getActivity(), "Please install Google Play Store and retry again!", Toast.LENGTH_LONG).show();
      getActivity().finish();
    }
  }

  @Override
  public void onResume() {
    super.onResume();
    this.mapView.onResume();
    this.handler.onMapResume(this.mapView.getMap());
  }

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

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

  @Override
  public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    this.mapView.onSaveInstanceState(outState);
  }

  @Override
  public void onLowMemory() {
    super.onLowMemory();
    this.mapView.onLowMemory();
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
      this.handler = (Handler) activity;
    } catch (ClassCastException e) {
      throw new ClassCastException("Your activity has to implement the interface " + this.handler.getClass().getName());
    }
  }

  public AppMapFragment() {
  }

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

    ((ViewGroup) rootView.findViewById(R.id.mapViewHolder)).addView(this.mapView);

    return rootView;
  }
}
person comeGetSome    schedule 10.12.2013

Одно различие между MapFragment и MapView заключается в том, что вы должны вручную управлять жизненным циклом MapView, в то время как MapFragment позаботится об этом сам.

Вы должны вызывать следующие методы из соответствующих методов родительского Activity/Fragment.

onCreate(Bundle)
onResume()
onPause()
onDestroy()
onSaveInstanceState()
onLowMemory()

Я проверил это с помощью RawMapViewDemoActivity в примерах сервисов Google Play, которые можно установить в разделе «Дополнительно» Android SDK Manager.

В примере сначала была показана карта, а после того, как я закомментировал 6 строк mMapView.onXXX(), она показала пустую страницу.

Возможно, жизненный цикл является причиной того, что большинство примеров, которые мы видим повсюду, используют MapFragment.

person Alpha Huang    schedule 06.07.2014
comment
Почему они исключили MapActivity из v1 v2? - person GPrimola; 18.07.2014

Попробуйте так:

  private MapView myMapView;   
  private GoogleMap map;  
      myMapView = (MapView) findViewById(R.id.map);     
      if (map == null) {     
                map = ((MapView) findViewById(R.id.map)).getMap();     
       }
person GrIsHu    schedule 25.01.2013
comment
К сожалению, не работает :( Выдает эту ошибку 01-25 16:44:20.063: E/AndroidRuntime(20332): Вызвано: java.lang.ClassCastException: android.widget.FrameLayout нельзя преобразовать в com.google.android .gms.maps.MapView, и это указывает на строку myMapView = (MapView) findViewById(R.id.map); - person lyk; 25.01.2013
comment
Можете ли вы сказать мне, какой минимальный API вы используете? - person GrIsHu; 25.01.2013
comment
Я полагаю, вы имеете в виду это? андроид: minSdkVersion = 9 - person lyk; 25.01.2013
comment
Тогда вам следует использовать SupportMapFragment, потому что MapFragment предназначен для API 12 или выше. Вот почему это исключение. - person GrIsHu; 25.01.2013
comment
Я использую MapView, а не MapFragment. Поскольку карта будет занимать весь экран, мне не требуется реализовывать MapFragment. Влияет ли версия SDK на использование класса MapView? - person lyk; 25.01.2013
comment
Попробуйте использовать SupportMapFragment вместо MapView. - person GrIsHu; 25.01.2013
comment
Да, SDK влияет на MapView, вот почему. Я думаю, вы должны расширить android.support.v4.app.FragmentActivity в своей деятельности POnlineMapView вместо Activity - person GrIsHu; 25.01.2013
comment
Я действительно пытаюсь избегать фрагментов, поскольку я не знаком с ними... но я думаю, мне нужно изучить, чтобы увидеть, как это работает... Итак, могу ли я по-прежнему использовать MapView, если вместо этого я расширяю активность фрагментов? - person lyk; 25.01.2013

Мне тоже не повезло с видом карты.
Мне повезло с MapFragment.

Попробуй это:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

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.LatLng;

public class TestActivity extends FragmentActivity {

  SupportMapFragment mapFragment;
  GoogleMap map;

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

    if (mapFragment == null) {
      mapFragment = new SupportMapFragment();
      getSupportFragmentManager().beginTransaction()
          .add(android.R.id.content, mapFragment).commit();
    }
  }

  @Override
  protected void onResume() {
    super.onResume();
    setupMap();
  }

  private void setupMap() {
    if (map != null)
      return;
    map = mapFragment.getMap();
    if (map == null)
      return;

    doZoom();
  }

  private void doZoom() {
    if (map != null) {
      map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(45.424900,
          -75.694968), 17));
    }
  }
}
person Dan Brough    schedule 31.01.2013