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を使う際には注意が必要です。