2010年11月9日火曜日

AsyncTaskを使った場合ItemizedOverlayのリストを更新するときはMapViewのinvalidate()を忘れずに

AsyncTaskクラスのサブクラスを作って、バックグラウンドでリクエストデータを処理し、MapView上のItemizedOverlayを更新する処理を行っていた。

ところが、タップしないとアイテムがマップ上に描画されないという症状にはまり、試行錯誤。

結局、MapViewにアタッチされたItemizedOverlayを更新した際にはMapViewのinvalidate()をコールして強制的にビューを再描画させる、ということが肝だった。

参考にしたのは以下のページ。
Maps/NooYawkAsync/src/com/commonsware/android/maps/NooYawk.java at master from commonsguy's cw-advandroid - GitHub
public void onPreExecute() {
   if (sites!=null) {
    map.getOverlays().remove(sites);
    map.invalidate(); 
    sites=null;
   }
  }

  @Override
  public Void doInBackground(Void... unused) {
   SystemClock.sleep(5000);      // simulated work

   sites=new SitesOverlay();

   return(null);
  }

  @Override
  public void onPostExecute(Void unused) {
   map.getOverlays().add(sites);
   map.invalidate();   
  }

上記のソースでは、onPreExecute()でItemizedOverlayを削除し、onPostExecute()で追加するという処理が行れている。

しかし、試してみたところ、その処理は必要ない。
ItemizedOverlayはアプリケーション起動時からMapViewに追加しっぱなしでアイテムリストの更新ができた。

ただ肝は、onPostExecute()のinvalidate()だ。これは忘れちゃいけない。


以下はMyソース。
@Override
 protected void onPostExecute(ArrayList<OverlayItem> result) {

  GeoItemizedOverlay geoOverlay = (GeoItemizedOverlay) mapView
    .getOverlays().get(0);

  // 現在オーバーレイに追加されているアイテムを削除する
  geoOverlay.clear();
  geoOverlay.populateOverlay();

  // オーバーレイにアイテムを追加してpopulate()を呼ぶ
  geoOverlay.addAll(result);
  geoOverlay.populateOverlay();
  mapView.invalidate();
 }

ドキュメントを見ると、ちゃんとinvalidate()がビューを強制的に再描画させるメソッドであることが書いてある。
How Android Draws Views | Android Developers

You can force a View to draw, by calling invalidate().

ドキュメントはよーくチェックしないといけませんな。