Google Maps 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);    
    }
}

Ответ 2

Это похоже на старый вопрос, но у меня была та же проблема, что и при использовании MapView.

Предполагая, что вы правильно импортировали библиотеку Google Play Services, вы должны проверить, есть ли у вас доступ к сервисам Google, вы можете сделать это в методе onCreate, и вам нужно инициализировать AP Google Maps Android. вы можете сделать это, добавив следующий код к методу 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();
}

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

@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"/>

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

Ответ 3

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

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

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

Ниже мой CustomMapFragment, который я использую с раскладкой макета (с возможностью сложной компоновки) и встроенной картой, вы можете ее использовать. Вы также можете расширить фрагмент из поддержки lib, а не 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;
  }
}

Ответ 4

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

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

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

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

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

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

Ответ 5

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

  private MapView myMapView;   
  private GoogleMap map;  
      myMapView = (MapView) findViewById(R.id.map);     
      if (map == null) {     
                map = ((MapView) findViewById(R.id.map)).getMap();     
       }

Ответ 6

Мне тоже не повезло с видом карты.
Мне повезло с 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));
    }
  }
}