2013-10-28 14 views
11

アンドロイドのシングルタップメソッドでマーカーを描画しようとしています。マーカーを描くと描画されますが、描画に時間がかかります。つまり、30〜40ミリ秒に2〜3秒かかることがあります。ここで私は描画メソッドを持っているクラスのための私のコードです。キャンバスandroidのonDraw()メソッドでBitmapを高速に描画する方法

public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> { 

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

    public MyItemizedOverlay(Drawable pDefaultMarker, 
      ResourceProxy pResourceProxy) { 
     super(pDefaultMarker, pResourceProxy); 
    } 

    @Override 
    public void draw(Canvas canvas, MapView mapView, boolean arg2) { 
     super.draw(canvas, mapView, arg2); 

     // ---translate the GeoPoint to screen pixels--- 
     Point screenPts = new Point(); 
     mapView.getProjection().toPixels(p, screenPts); 

     // ---add the marker--- 
     Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_darkblue); 
     Bitmap bmp1 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_green); 
     Bitmap bmp2 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_bue); 
     Bitmap bmp3 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_light); 
     Bitmap bmp4 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_light); 
     Bitmap bmp5 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_light); 
     Bitmap bmp6 = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_light); 
     if (count == 1) { 
      int caller = getIntent().getIntExtra("button", 0); 
      switch (caller) { 
      case R.id.btMap: 
       canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
       bmp.recycle(); 
       break; 
      case R.id.imageButton1: 
       canvas.drawBitmap(bmp1, screenPts.x, screenPts.y - 50, null); 
       bmp1.recycle(); 
       break; 
      case R.id.imageButton2: 
       canvas.drawBitmap(bmp2, screenPts.x, screenPts.y - 50, null); 
       bmp2.recycle(); 
       break; 
      case R.id.imageButton3: 
       canvas.drawBitmap(bmp3, screenPts.x, screenPts.y - 50, null); 
       bmp3.recycle(); 
       break; 
      case R.id.imageButton4: 
       canvas.drawBitmap(bmp4, screenPts.x, screenPts.y - 50, null); 
       bmp4.recycle(); 
       break; 
      case R.id.imageButton5: 
       canvas.drawBitmap(bmp5, screenPts.x, screenPts.y - 50, null); 
       bmp5.recycle(); 
       break; 
      case R.id.imageButton6: 
       canvas.drawBitmap(bmp6, screenPts.x, screenPts.y - 50, null); 
       bmp6.recycle(); 
       break; 
      } 
     } 
     // Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
     // R.drawable.pin_annotation_green); 
     // if (count == 1) { 
     // canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
     // } 
} 

答えて

18

すべてのビットマップをコンストラクタで初期化する必要があります。ビットマップのデコードに時間がかかります。 HashMap(キー、値)を使用してそれらを保存できます。次に、onDrawで、一致したビットマップを取得し、直接描画します。ここで

public class MyView extends View{ 

    private HashMap<String, Bitmap> mStore = new HashMap<String, Bitmap>(); 
    public MyView(Context context) { 
     super(context); 
     // TODO Auto-generated constructor stub 

     init(); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     // TODO Auto-generated method stub 

     int caller = getIntent().getIntExtra("button", 0); 
     Bitmap bmp = null; 
     switch (caller) { 
     case R.id.btMap: 
      bmp = mStore.get(R.id.btMap); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      bmp = null; 
      break; 
     case R.id.imageButton1: 
      bmp = mStore.get(R.id.imageButton1); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp1.recycle(); 
      bmp1 = null; 
      break; 
     } 

     super.onDraw(canvas); 
    } 

    public void init() { 
     Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_darkblue); 
     mStore.put(R.id.btMap, bmp); 

     bmp = BitmapFactory.decodeResource(getResources(), 
       R.drawable.pin_annotation_green); 
     mStore.put(R.id.imageButton1, bmp); 
    } 
} 

例えば

は、私はあなたのコードに基づいて行われてきたものです。重複したリソースIDを確認する必要があります。

private ArrayList<OverlayItem> overlayItemList = new ArrayList<OverlayItem>(); 
private HashMap<String, Bitmap> mStore = new HashMap<String, Bitmap>(); 

public MyItemizedOverlay(Drawable pDefaultMarker, 
     ResourceProxy pResourceProxy) { 
    super(pDefaultMarker, pResourceProxy); 

    Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_darkblue); 
    mStore.put(R.id.btMap, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_green); 
    mStore.put(R.id.imageButton1, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_bue); 
    mStore.put(R.id.imageButton2, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_light); 
    mStore.put(R.id.imageButton3, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_light); // check it 
    mStore.put(R.id.imageButton4, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_light); // check it 
    mStore.put(R.id.imageButton5, bmp); 
    bmp = BitmapFactory.decodeResource(getResources(), 
      R.drawable.pin_annotation_light); // check it 
    mStore.put(R.id.imageButton6, bmp); 

} 

@Override 
public void draw(Canvas canvas, MapView mapView, boolean arg2) { 
    super.draw(canvas, mapView, arg2); 

    // ---translate the GeoPoint to screen pixels--- 
    Point screenPts = new Point(); 
    mapView.getProjection().toPixels(p, screenPts); 

    // ---add the marker--- 
    if (count == 1) { 
     int caller = getIntent().getIntExtra("button", 0); 
     Bitmap bmp = null; 

     switch (caller) { 
     case R.id.btMap: 
      bmp = mStore.get(R.id.btMap); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton1: 
      bmp = mStore.get(R.id.imageButton1); 
      canvas.drawBitmap(bmp1, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton2: 
      bmp = mStore.get(R.id.imageButton2); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton3: 
      bmp = mStore.get(R.id.imageButton3); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton4: 
      bmp = mStore.get(R.id.imageButton4); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton5: 
      bmp = mStore.get(R.id.imageButton5); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     case R.id.imageButton6: 
      bmp = mStore.get(R.id.imageButton6); 
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
      bmp.recycle(); 
      break; 
     } 
    } 
    // Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
    // R.drawable.pin_annotation_green); 
    // if (count == 1) { 
    // canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 50, null); 
    // } 
} 
+0

私たちは、[チャットでこの議論を続ける]みましょう(http://chat.stackoverflow.com/rooms/40102/discussion-between-gaurav-kumar-and-yushulx)コードを共有するためのおかげで –

+0

。しかし、私はあなたが最初の例でスイッチが必要とは思わない。これを行うだけです: 'int caller = getIntent()。getIntExtra(" button "、0); ビットマップbmp = mStore.get(呼び出し元); canvas.drawBitmap(bmp、screenPts.x、screenPts.y - 50、null); bmp.recycle(); bmp = null; 休憩。 } ' –

2

お客様のdraw()メソッドからすべてBitmapFactory.decodeResource()通話を削除する必要があります。ビットマップを一度だけデコードし、参照を保持します。その後draw()メソッドでcanvas.drawBitmap()に電話するだけです。

7

コードを最適化するという考えは、描画に必要な操作だけを実行することです。だから、あなたはあなたのonDrawメソッドから削除する必要があります:

  • 任意のインスタンス化:彼らはしばしば呼ばれ、多くの新しいオブジェクトを作成したくないので、時間がかかる。 onLayout中にscreenPtsを格納し、常に同じ点を再利用します。
  • BitmapFactory.decodeResource:これにはかなりの時間がかかります。最初にビットマップをデコードし、それらを格納し、onDrawの間だけ描画します。
  • ビットマップをリサイクルするときは、必要がなくなったらリサイクルしてください。例えば

  • 復号化は非同期タスクの内部で発生したonPause中にそれらをリサイクルonResume中にビットマップをデコードします。非同期タスクが終了したら、onDrawにイメージが準備完了で描画可能であることを示すフラグを立てます。
  • 長い時間がかかるので、バックグラウンドで画像をデコードすることは非常に重要です。メインのUIスレッドでこれをしないでください。さもなければあなたのアプリは応答しないように見える
  • あなたのscreenPtsをonLayoutの中で計算し、常に同じ点を再利用します。
  • onDrawの間にgetIntentを呼び出さないでください。

簡単に言えば、onDrawの操作を最小限に抑えて、約60FPSの非常に高速な描画を実現します。

また、(醜い)スイッチを削除し、ハッシュマップを使用してカウントの値とビットマップを関連付けることを検討する必要があります。配列はもっと速く、ここではもっと適切かもしれません。

+0

私にいくつかのコードを教えてください。私はこれ以上接していないからです。 –

+4

@gaurav kumar私は上記の答えは完全ではないと思うコードが必要です。まず、活動のライフサイクルを理解しようとすると、上記のことを簡単に適用できます。どのメソッドといつ呼び出されるのか何度知るべきです。次に、コードを再利用し、常にスレッドや非同期タスク(Androidで推奨)を使用してUIスレッドから重いコードを削除してください。 "Snicolas"によって与えられるコンセプトは非常に一般的であり、すべてのプラットフォームに適用できます。 –

関連する問題