LoginSignup
14
14

More than 5 years have passed since last update.

Google Maps Android API v2の不具合と対策法

Last updated at Posted at 2014-01-24

何の記事?

Google Maps Android APIでv1からv2に移行する際に詰まった点とその対策法についてです。
Google Maps Android APIはv1からv2で大きく仕様が変わっています。
参考:Google Maps Android API v2 の v1 からの変更点メモ

不具合って?

  1. v2ではマーカーをタップした時にポップアップウィンドウ(InfoWindow)を出す機能が標準装備されました。しかし,titleやsnippetには対応しているものの,他のデータを渡すことが出来ません(setData(obj)みたいなメソッドが用意されていない)。例えば,下記のようなInfoWindowを作成するには,画像のURL(もしくはデータ)を渡す必要がありますが,ミッション・インポッシブル。
    スクリーンショット 2014-01-24 5.32.18 PM.png

  2. InfoWindowに,リモートにある画像を表示しようとすると,別のマーカーをタップしてもそのマーカー用の画像が表示されずに,一つ前のマーカー用の画像が表示されてしまいます。(ビューの生成タイミングの問題だと思います)

  3. LatLngのリストを渡して,全てのマーカーが地図内に入るようにズームレベルを調整するケースがよくあると思います。しかし,そのメソッドであるmoveCameraでは,"java.lang.IllegalStateException: Map size should not be 0. Most likely, layout has not yet occured for the map view."というエラーが発生するケースがあります。

対処法

InfoWindowにデータを渡す

Markerを生成すると自動的にMarkerのプロパティとしてIdが付与されます。これを利用して,各Markerに対応したデータをHashMapに渡します。

TemplateMapActivity.java
public class TemplateMapActivity extends FragmentActivity {
    private HashMap<String, String> hashMap             = new HashMap<String, String>();

public Marker createMarker(LatLng latLng, String title, String snippet) {
        MarkerOptions options = new MarkerOptions();
        options.position(latLng);
        options.title(title);
        options.snippet(snippet);
        Marker marker = map.addMarker(options);
        hashMap.put(marker.getId(), "HogeHoge");
        return marker;
    }
}

MyInfoWindowAdapter.java
public class MyInfoWindowAdapter implements InfoWindowAdapter {
    private final View  window;
    private HashMap<String, String> hashMap;

    public MyInfoWindowAdapter(Context context, HashMap<String, String> hashMap) {
        LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        window = inflater.inflate(R.layout.infowindow, null);
        this.hashMap = hashMap;
    }
@Override
    public View getInfoWindow(Marker marker) {
        render(marker, window);
        return window;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null;
    }

    private void render(final Marker marker, View view) {
        TextView tv_title = (TextView) view
                        .findViewById(R.id.infowindow_title);
        TextView tv_snippet = (TextView) view
                        .findViewById(R.id.infowindow_snippet);

        tv_title.setText(marker.getTitle());
        tv_snippet.setText(marker.getSnippet());

        // getting "HogeHoge"
        hashMap.get(marker.getId())
    }
}

InfoWindow内画像データの更新

リモートにある画像をInfowWindowで表示しようとすると画像の取得処理をAsyncTask内に書く必要があり,その間にメインスレッドはgetInfoWindowを終えてしまい,後からViewの更新ができません。そこで,下記のように画像をロードした段階で再描画します。また,無限ループに入るのを防ぐために最後に描画したMarkerを記憶します。(ここでは,リモート画像の取得処理に,SmartImageViewを使用しています)

MyInfoWindowAdapter.java
public class MyInfoWindowAdapter implements InfoWindowAdapter {
    private final View  window;
    private HashMap<String, String> hashMap;
    private String                  lastMarkerId;

    public MyInfoWindowAdapter(Context context, HashMap<String, String> hashMap) {
        LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        window = inflater.inflate(R.layout.infowindow, null);
        this.hashMap = hashMap;
    }

    @Override
    public View getInfoWindow(Marker marker) {
        render(marker, window);
        return window;
    }

    @Override
    public View getInfoContents(Marker marker) {
        if (marker != null && marker.isInfoWindowShown()) {
            marker.showInfoWindow();
        }
        return null;
    }

    private void render(final Marker marker, View view) {
        if (marker.getId().equals(lastMarkerId))
            return;
        lastMarkerId = marker.getId();

        icon.setImageUrl(
                        // get unique URL
                        hashMap.get(marker.getId()),
                        new OnCompleteListener() {
                            @Override
                            public void onComplete() {
                                getInfoContents(marker);
                            }
                        });
    }
}

map.moveCameraでエラーが出る

エラーが何故起きるかのよくわかる解説はコチラmoveCamera(CameraUpdateFactory.newLatLngBounds(… で落ちる

上記でもできるが,こんな書き方もできます。

TemplateMapActivity.java
public void setZoom(List<LatLng> latLngList) {
    if (map == null || latLngList.size() == 0)
        return;

    final LatLngBounds.Builder builder = LatLngBounds.builder();
    for (LatLng latLng : latLngList) {
        builder.include(latLng);
    }

    map.setOnCameraChangeListener(new OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition arg0) {
            map.moveCamera(CameraUpdateFactory.newLatLngBounds(
                                builder.build(), 40));
            map.setOnCameraChangeListener(null);
        }
    });
}
14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14