2013-10-28 15 views
11

Ich versuche, eine Markierung auf Single-Tap-Methode in Android zu zeichnen. Wenn ich den Marker zeichne, wird er zeichnen, aber es wird mehr Zeit zum Zeichnen brauchen, d. h. 30 bis 40 Millisekunden, manchmal dauert es 2-3 Sekunden. Hier ist mein Code für Klasse, in der ich zeichne Methode habe.Wie zeichne Bitmap schnell in onDraw() -Methode in Canvas Android

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); 
     // } 
} 

Antwort

18

Sie sollten alle Bitmaps in Constructor initialisieren. Das Dekodieren von Bitmap dauert sehr lange. Sie können einen HashMap (Schlüssel, Wert) verwenden, um sie zu speichern. Dann in onDraw, erhalten Sie die passende Bitmap und zeichnen Sie es direkt.

Zum Beispiel

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); 
    } 
} 

Hier ist, was ich auf der Grundlage Ihrer Code getan haben. Sie müssen einige doppelte Ressourcen-IDs überprüfen.

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

Lassen Sie uns [diese Diskussion im Chat fortsetzen] (http://chat.stackoverflow.com/rooms/40102/discussion-between-gaurav-kumar-and-yushulx) –

+0

Vielen Dank für die Freigabe des Codes. Aber ich glaube nicht, dass du den Schalter im ersten Beispiel brauchst. Tun Sie das einfach: 'int caller = getIntent(). GetIntExtra (" button ", 0); Bitmap bmp = mStore.get (Aufrufer); canvas.drawBitmap (bmp, screenPts.x, screenPts.y - 50, null); bmp.recycle(); bmp = null; Pause; } ' –

2

Sie sollten alle BitmapFactory.decodeResource() Anrufe von Ihrem draw() Methode entfernen. Dekodieren Sie die Bitmap nur einmal und behalten Sie den Verweis darauf. Dann rufen Sie einfach canvas.drawBitmap() in Ihrer draw() Methode.

7

Die Idee zur Optimierung Ihres Codes besteht darin, nur die zum Zeichnen erforderlichen Operationen auszuführen. Also sollten Sie von Ihrer onDraw-Methode entfernen:

  • beliebige Instanziierung: Sie dauern lange, onDraw wird oft aufgerufen und Sie möchten nicht so viele neue Objekte erstellen. Speichern Sie screenPts während onLayout und verwenden Sie immer die gleichen Punkte.
  • BitmapFactory.decodeResource: Das dauert ziemlich lange. Dekodiere dein Bitmap zuerst, speichere es und zeichne es nur während onDraw.
  • recyceln Sie die Bitmaps, wenn Sie sie nicht mehr benötigen, nicht jedes Mal, wenn Sie sie gezeichnet haben.
  • Zum Beispiel:

    • dekodieren Ihre Bitmaps während onResume
    • recyceln sie während onPause
    • Decodierung innerhalb eines Asynchron-Aufgabe auftreten sollte. Wenn die asynchrone Aufgabe beendet ist, heben Sie ein Flag an, um onDraw anzuzeigen, dass Bilder bereit sind und gezeichnet werden können.
    • es ist sehr wichtig, Bilder im Hintergrund zu dekodieren, da es eine lange Zeit dauert. Tun Sie dies nicht im Haupt-UI-Thread. Andernfalls reagiert Ihre App nicht mehr.
    • berechnen Sie Ihre screenPts innerhalb onLayout und verwenden Sie die gleichen Punkte die ganze Zeit.
    • GetIntent während onDraw auch nicht aufrufen.
    • Kurz gesagt, minimieren Sie die Operationen während onDraw und Sie werden sehr schnell zeichnen, etwa 60 FPS.

      Sie sollten auch in Betracht ziehen, diesen (hässlichen) Schalter zu entfernen und eine hashmap verwenden, um die Werte von count und der zu zeichnenden Bitmap zuzuordnen. Ein Array wäre hier sogar schneller und vielleicht passender.

    +0

    können Sie mir einen Code geben. weil ich nicht mehr daran grenze. –

    +4

    @gaurav kumar Ich denke, die obige Antwort ist vollständig und denke nicht, dass Code erforderlich ist. Zuerst versuchen Sie den Aktivitätslebenszyklus zu verstehen, dann können Sie leicht über die Dinge hinausgehen.Sie sollten verstehen, wie oft welche Methode und wann es aufgerufen wird. Versuchen Sie dann, Ihren Code wiederzuverwenden und immer Threads oder asynchrone Aufgaben zu verwenden (empfohlen in Android), um schweren Code aus UI-Threads zu entfernen, und Sie sind fertig. Konzept von "Snicolas" ist sehr generisch und kann auf allen Plattformen angewendet werden. –

    Verwandte Themen