ラベル Google Maps の投稿を表示しています。 すべての投稿を表示
ラベル Google Maps の投稿を表示しています。 すべての投稿を表示

2010年12月21日火曜日

Android アプリでGoogle Maps のズームイン/アウト時に何らかのイベントを処理したい場合はOnZoomListener を実装する

Androidアプリで、Google Mapsのズームイン/ズームアウト時に何らかのイベントを処理したい場合は、OnZoomListener を実装する。

import android.os.Bundle;
import android.util.Log;
import android.widget.ZoomButtonsController.OnZoomListener;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

public class MapDemoActivity extends MapActivity implements OnZoomListener {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  createMapView();
 }

 private void createMapView() {
  mapView = (MapView) findViewById(R.id.mapview);
  // デフォルトのズームコントローラーを使用する
  mapView.setBuiltInZoomControls(true);
  // ズームコントローラーのイベントを処理するリスナーを設定する
  mapView.getZoomButtonsController().setOnZoomListener(this);
 }

 @Override
 public void onZoom(boolean zoomIn) {
  if (zoomIn ? mapView.getController().zoomIn() : mapView.getController()
    .zoomOut());
  Log.i(LOGTAG, "onZoom():zoomIn=" + zoomIn);

  // タスクを実行する
  executeTask();
 }

 @Override
 public void onVisibilityChanged(boolean visible) {
 }

onZoomListener を実装すると、必ず、onZoom() とonVisibilityChanged() をオーバーライドしなければならない。

onZoom() は、正に、ズームイン/ズームアウト時に呼ばれるメソッドであり、onVisibilityChanged() は、デフォルトのズームコントローラーの表示/非表示が切り替わったときに呼ばれるメソッド。特に行いたい処理が無くても、これら2つのメソッドは記述する必要がある。


注意点としては、onZoom() の処理をオーバーライドするので、自分でzoomIn() やzoomOut() を呼ばなくてはいけなくなること。zoomIn()/zoomOut() をコールしないと、マップがズームイン/ズームアウトしなくなる。

2010年12月8日水曜日

Galaxy Tabでストリートビューを試す。ここにいたのか、ペグマン!

Google MapsのAndroidアプリで、どこからどうやればストリートビューモードになるのかずーっと分からなかったが、ようやく操作方法を発見。

まず、ストリートビューで見たい場所をマップ上でタップして長押し。すると、その場所の住所や画像などのダイアログが表示される。

ダイアログをタップすると、画面右端にストリートビューのキャラクター「ペグマン」が!君はここにいたのか!

ペグマンをタップすると、あっさりストリートビュー起動。画面右下のペグマンをドラッグ。

進みたい場所へドロップ。

ストリートビューで表示している場所が、ペグマンをドロップした場所に変わる。


Wi-Fi環境だとストリートビューの表示も軽快で、Galaxy Tabくらい大きな画面でも、さくさくバーチャルお散歩ができるなあ。

2010年11月15日月曜日

iTouch Glovesは素手と同じ操作感

picnic inc.から販売されている「iTouch Gloves」を買ってみました。
iTouch Glovesアイタッチグローブ -スマートフォンなどのタッチパネル式携帯で使える手袋-

ちなみに、iTouch GlovesでiPad上のGoogle Mapsを操作しているところを、ビデオで撮ってみました。



素手と同じ感覚で操作できます。

そして当然ですが、温かい(^^)。

手触りは普通に手袋で、思ったより柔らかかったです。

難点を強いてあげるとすれば、タイピングの時にローマ字入力を選択していると、素手で操作している時よりもミスタイプが増えるかなという点と、既に少しほつれが出てきたという点でしょうか(^^;)。
言うても、1,890円ですからね。


しかし、既にこういうものも・・・。
着けたままiPhoneを使えるおしゃれな手袋「EVOLG」 - Touch Lab - タッチ ラボ




こちらの方がカラフルでカワイイかも・・・。

でも、プライベートではいいけれど、ビジネスでははめていけないじゃないと思って、自分を納得させました(^^;)。

2010年11月4日木曜日

ドイツ国内の一部でGoogle MapsのStreet View機能が導入される。いつのまにかGoogle Mapsの表示が若干セカイカメラっぽくなっている。

11月2日、Google MapsのStreet View機能がドイツ国内の一部に導入された。
現在は20都市5つのランドマークのみに対応している。
Google LatLong: A special preview of beautiful Germany in Street View

ストリートビューのドイツ導入は、個人のプライバシーを侵害するとして反対が多く、なかなか進まないと報じられていたが、写真を見ると、なんだかすごくウェルカムな雰囲気の写真が多い(^^;)。
Picasa ウェブ アルバム - a+o GmbH - Street View s...


反対が多くても、Googleは、オプトアウト(個人宅の画像をぼかすといった対応)の申請を受け付けるとして、ストリートビューのドイツ対応を実施する予定だ。こういった面でもオプトアウトというのがGoogleらしい。

10月21日のGoogleのブログ記事によると、このオプトアウトについて、24万4237世帯から求められたとある。この数は対象地域845万8084世帯の2.89%に当たる。これ全部に対応するのは大変そうだ。
European Public Policy Blog: How many German households have opted-out of Street View?

ドイツだけでなく、イタリアでも、地図にマッピングされる前に市民に知らせるように要請されたり、チェコでは、やはりプライバシーを侵害するとして今以上の画像のキャプチャーは禁止されている。ヨーロッパは、プライバシーの侵害について、かなりセンシティブなんですね。
BBC News - German Street View goes live with enhanced privacy


それにしても、今回、ドイツのランドマークのストリートビューを見ていて、Google Mapsの見えが若干セカイカメラっぽくなっていて、驚きました。ストリートビューをスクロールしている時に、Panoramioの写真やGoogle Placesアイコンがマッピングされたり。セカイカメラを参考にしたんでしょうか。

※埋め込んだGoogle Mapsの下にある「View Larger Map」をクリックすると確認できます。

View Larger Map

2010年11月1日月曜日

ItemizedOverlay 使用時にたまにArrayIndexOutOfBoundsException が発生するバグへの対応

com.google.android.maps.ItemizedOverlayを使って地図上にアイテムを配置すると、アイテムをタップした際に、たまにArrayIndexOutOfBoundsExceptionが発生して困った。

この問題を解決するには、setLastFocusedIndex(-1)をpopulate()の前にコールする。

APIドキュメントによると、フォーカスが変わったときに自動的にアップデートされるので、ItemizedOverlayを継承したサブクラスで、フォーカスのインデックスを変更する必要はない、と書かれているが・・・。

実際は、リスト更新時に、populate()の前に自分でsetLastFocusedIndex(-1)を呼び、どのアイテムにもフォーカスが設定されていない状態を作らないといけない。

public class GeoItemizedOverlay extends ItemizedOverlay<OverlayItem> {

 private ArrayList<OverlayItem> overlayArrayList = new ArrayList<OverlayItem>();

 public void add(OverlayItem overlay) {
  overlayArrayList.add(overlay);
 }

 public void clear() {
  overlayArrayList.clear();
 }

 public void populateOverlay() {

  // 必ずpopulate()の前にsetLastFocusedIndex(-1)を実行する
  // そうしないと、リストが変わった際にアイテムのインデックスがずれる場合がありArrayIndexOutOfBoundsExceptionが発生することがある
  // http://groups.google.com/group/android-developers/browse_thread/thread/38b11314e34714c3
  setLastFocusedIndex(-1);
  populate();
 }
}

オーバレイアイテム更新時には、clear()やadd()し終わった際には必ずpopulateOverlay()を呼ぶようにする。

// 現在オーバーレイに追加されているアイテムを削除する
geoOverlay.clear();
// 必ずsetLastFocusedIndex(-1)とpoopulate()を実行
geoOverlay.populateOverlay();

for (int i = entries.getLength() - 1; i >= 0; i--) {

 OverlayItem overlayItem = new OverlayItem(・・・);
 // アイテムを追加
 geoOverlay.add(overlayItem);

}

// 必ずsetLastFocusedIndex(-1)とpoopulate()を実行
geoOverlay.populateOverlay();

解決には以下の記事を参考にさせていただいた。
ItemizedOverlay & ArrayIndexOutOfBoundsException > explanation AND solution !! - Android Developers | Google グループ

Android – ItemizedOverlay + ArrayIndexOutOfBoundsException / NullPointerException workarounds « Developmentality


先日のNullPointerExceptionが発生する件といい、ItemizedOverlayを使う際には注意が必要です。

2010年10月26日火曜日

タッチイベントはMapViewとItemizedOverlayのどちらにまず伝わるのか

Android+Google MAP APIでタッチイベントを処理する時のイベントの流れを確認する。
使ったのは以下のクラス。

・MapDemoActivityクラス
MapActivityを継承したクラス。実行クラス。

・CusomizedMapViewクラス
MapViewを継承したクラス。MapDemoActivityのContentViewとして設定。

・GeoItemizedOverlayクラス
ItemizedOverlayを継承したクラス。


これらのクラスは、下から積み上げると以下のような階層関係にある。

GeoItemizedOverlay
|
CusomizedMapView
|
MapDemoActivity


・検証

ディバイスの画面にタッチしたときには、onTouchEvent(MotionEvent event)が呼び出される。

MapViewを使ったときは、Activityに記述したonTouchEventではなくMapView側のonTouchEventが呼び出されることは、前の記事に書いた。

では、MapViewにItemizedOverlayが追加されているときは、タッチイベントはMapViewとItemizedOverlayのどちらにまず伝わるのか。

public class MapDemoActivity extends MapActivity {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  /** マップビュー作成 */
  CustomizedMapView mapView = (CustomizedMapView) findViewById(R.id.mapview);

  Drawable drawable = this.getResources().getDrawable(R.drawable.star);
  GeoItemizedOverlay geoOverlay = new GeoItemizedOverlay(drawable, this);

  /** オーバーレイをマップに追加 */
  List<Overlay> mapOverlays = mapView.getOverlays();
  mapOverlays.add(geoOverlay);
 }
}
public class CustomizedMapView extends MapView {
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  Log.i("onTouchEvent", "CustomizedMapView.onTouchEvent");
  return super.onTouchEvent(event);
 }
}
public class GeoItemizedOverlay extends ItemizedOverlay<OverlayItem> {
 @Override
 public boolean onTouchEvent(MotionEvent event, MapView mapView) {
  Log.i("onTouchEvent", "GeoItemizedOverlay.onTouchEvent");
  return super.onTouchEvent(event, mapView);
 }
}

試してところ、ItemizedOverlayよりも先にMapViewへタッチイベントが伝わることが分かった。
10-26 13:29:55.577: INFO/MapDemo(4253): CustomizedMapView.onTouchEvent
10-26 13:29:55.577: INFO/MapDemo(4253): GeoItemizedOverlay.onTouchEvent

上記のクラスで言うと、

CustomizedMapView→GeoItemizedOverlay

の順番だ。


・結論

MapView側に記述してあるonTouchEventがまず呼ばれる。

そして、MapViewのonTouchEventの最後に実行する、super.onTouchEvent(event)により、MapViewに追加されている各Overlayへタッチイベントが伝えられていく、という流れのようだ。

ItemizedOverlayをMapViewに追加しているときにアイテムが無いとNullPointerExceptionが発生するバグへの対応

ItemizedOverlayがMapViewに追加されているときは、MapViewクラスのonTouchEvent(MotionEvent event)が実行される際に、ItemizedOverlayのonTouchEvent(MotionEvent event)にもイベントが投げられる。

問題は、それがアイテム数が0の時にも起こるので、アイテム数が0の時に画面にタッチするとNullPointerExceptionが発生すること。

10-26 12:00:24.607: ERROR/AndroidRuntime(2753): java.lang.NullPointerException
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.ItemizedOverlay.getItemsAtLocation(ItemizedOverlay.java:617)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.ItemizedOverlay.getItemAtLocation(ItemizedOverlay.java:586)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.ItemizedOverlay.handleMotionEvent(ItemizedOverlay.java:498)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.ItemizedOverlay.onTouchEvent(ItemizedOverlay.java:572)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at hoge.MapDemo.GeoItemizedOverlay.onTouchEvent(GeoItemizedOverlay.java:54)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.OverlayBundle.onTouchEvent(OverlayBundle.java:63)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at com.google.android.maps.MapView.onTouchEvent(MapView.java:625)
10-26 12:00:24.607: ERROR/AndroidRuntime(2753):     at hoge.MapDemo.CustomizedMapView.onTouchEvent(CustomizedMapView.java:52)

今の所この現象を避けるには、ItemizedOverlayを継承したクラスのコンストラクタで、super(boundCenterBottom(defaultMarker));の後で、populate()を呼ぶこと。


・ItemizedOverlayを使うときは、必ずコンストラクタ内でpopulate()を呼ぶ

populate()はアイテムを追加した後に必ず呼ぶメソッドだが、アイテムがあろうがなかろうが、最初からコールしておくということ。これでNullPointerExceptionは発生しなくなる。

public class GeoItemizedOverlay extends ItemizedOverlay<OverlayItem> {

 private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
 private Context mContext;

 public GeoItemizedOverlay(Drawable defaultMarker, Context context) {
  super(boundCenterBottom(defaultMarker));
  mContext = context;
  populate();//これが大事!
 }
}

このバグはIssueとして管理されているので、早めに解決して欲しい方はvoteしてください。
Issue 2035 - android - NullPointerException when scrolling through a MapView with an ItemizedOverlay with no OverlayItems - Project Hosting on Google Code

MapView継承クラスでonTouchEvent()を処理するときに気をつけること

MapViewを利用すると、MapActivityを継承したクラス内にonTouchEvent(MotionEvent event)を書いてもイベントをキャッチできない。

以下のようなコードを書いても、MapViewの方にイベントが取られて、ログが出力されない。

public class MapDemo extends MapActivity {
 @Override
 public boolean onTouchEvent(MotionEvent event) {

  String action = "";
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   action = "ACTION_DOWN";
   break;
  case MotionEvent.ACTION_UP:
   action = "ACTION_UP";
   break;
  case MotionEvent.ACTION_MOVE:
   action = "ACTION_MOVE";
   break;
  case MotionEvent.ACTION_CANCEL:
   action = "ACTION_CANCEL";
   break;
  }

  Log.i("onTouchEvent", "action = " + action + ", " + "x = "
    + String.valueOf(event.getX()) + ", " + "y = "
    + String.valueOf(event.getY()));

  return super.onTouchEvent(event);
 }
}

そのため、MapViewクラスを継承したオリジナルのMapViewクラスを作成し、そのクラス内にonTouchEvent(MotionEvent event)を記述した。その時に気をつけること。


・MapViewクラスを継承する場合は、MapViewクラスのコンストラクタMapView(Context context, AttributeSet attrs)を必ずオーバーライドする

そうしないと、デフォルトのズームコントローラーを使ったり、フリップしてマップを動かすことができない。
静止画像のようにマップが表示されるだけの画面になってしまう。

コードは以下。

public class CustomizedMapView extends MapView {
 public CustomizedMapView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {

  String action = "";
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   action = "ACTION_DOWN";
   break;
  case MotionEvent.ACTION_UP:
   action = "ACTION_UP";
   break;
  case MotionEvent.ACTION_MOVE:
   action = "ACTION_MOVE";
   break;
  case MotionEvent.ACTION_CANCEL:
   action = "ACTION_CANCEL";
   break;
  }

  Log.i("onTouchEvent", "action = " + action + ", " + "x = "
    + String.valueOf(event.getX()) + ", " + "y = "
    + String.valueOf(event.getY()));

  return super.onTouchEvent(event);
 }
}
この時のレイアウトは以下。
<?xml version="1.0" encoding="utf-8"?>
<hoge.MapDemo.CustomizedMapView
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/mapview"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:clickable="true"
 android:apiKey="apiKey" />
MapView呼び出しはこんな感じ。
public class MapDemoActivity extends MapActivity {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  /** マップビュー作成 */
  CustomizedMapView mapView = (CustomizedMapView) findViewById(R.id.mapview);
 }
}

2010年10月13日水曜日

MyLocationOverlayを使うとDroidでクラッシュする場合がある

AndroidでGoogle Mapsを使っているときに、現在位置をMyLocationOverlayクラスを使って表示していると、Droidではクラッシュするらしい。

Androidアプリサービス開発者ブログ:Dorid & Droid X 端末でMapが強制終了してしまう件
The default MyLocationOverlay class crashes apps on Droid X | dimitar.me

上記の問題を解消したFixedMyLocationOverlayクラスを提供してくれている方がいらっしゃる。

特定の端末のみで発生するエラーに出くわすこともあるようだ。気をつけねば。

2009年10月29日木曜日

DroidのGoogle Maps Navigationはスゴそうだ!

DroidのGPSを使ったGoogle Mapsナビはスーパー・クール!

スーパー・クール、いいですねぇ。記者の興奮が伝わってきます。
実際に、YouTubeにあるGoogleの公式紹介ビデオを見ましたが、これは欲しくなります。
ちなみにビデオの中で彼が着ている「I am here.」というTシャツも欲しくなります(^^)



音声検索ができるし、ストリートビューに自動的に切り替わったりするし、ドックモードもあって、しかも無料。カーナビゲーションシステムを開発しているところは苦しくなるかもな、と心配になるくらいの出来ですね。

恐らく実際に動かしてみると、クラッシュしたり思い通りに動作しないところもあるのでしょうが、チューニングやバグフィックスが重ねられてソフトの品質が高まってくると、脅威でしょうね。


上記の公式紹介ビデオでは、実際に開発に当たっているGoogleのエンジニアの方がソフトの紹介をしていましたが、Google社員はプレゼン能力も高くないといけないんだなと思いました。そういった意味では、Googleはまるで大学の研究室のようでアカデミックですね。

YouTubeのGoogle DeveloppersのチャンネルにはGoogle社員がデモンストレーションやプレゼンテーションをしている多くのビデオがありますが、動画に対するコメントの中にプレゼン能力に対する言及も結構見受けられます。

Googleの社員はエンジニアとしてもプレゼンテーターとしても高い能力が求められるのでしょうね。