2013-10-28 13 views
11

Sto cercando di tracciare un marcatore sulla metodo alfanumerico singolo in Android. quando disegno il marcatore, si disegna ma ci vorrà più tempo per disegnare i 30-40 millisecondi, a volte ci vogliono 2-3 secondi. Ecco il mio codice per la classe in cui ho il metodo draw.Come disegnare bitmap velocemente in OnDraw() metodo in tela 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); 
     // } 
} 

risposta

18

Si dovrebbe inizializzare tutte le bitmap nel costruttore. Decodificare bitmap richiede molto tempo. È possibile utilizzare un HashMap (chiave, valore) per memorizzarli. Quindi in onDraw, ottieni la bitmap abbinata e disegnala direttamente.

Per esempio

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

Ecco quello che ho fatto sulla base di codice. Devi controllare alcuni ID di risorsa duplicati.

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

ci permetta [continua questa discussione in chat] (http://chat.stackoverflow.com/rooms/40102/discussion-between-gaurav-kumar-and-yushulx) –

+0

Grazie per aver condiviso il codice. Ma non penso che tu abbia bisogno dell'interruttore nel primo esempio. Basta fare questo: 'int caller = getIntent(). GetIntExtra (" button ", 0); Bitmap bmp = mStore.get (chiamante); canvas.drawBitmap (bmp, screenPts.x, screenPts.y - 50, null); bmp.recycle(); bmp = null; interruzione; } ' –

2

È necessario rimuovere tutte le BitmapFactory.decodeResource() le chiamate dal tuo metodo draw(). Decodificare bitmap solo una volta e mantenere il riferimento ad esso. Quindi chiama il numero canvas.drawBitmap() nel tuo metodo draw().

7

L'idea di ottimizzare il codice è quello di eseguire solo le operazioni necessarie per il disegno. Quindi, dovresti rimuovere dal tuo metodo onDraw:

  • qualsiasi instanciazione: richiedono molto tempo, onDraw viene chiamato spesso e non vuoi creare tanti nuovi oggetti. Memorizza schermate durante onLayout e riutilizza sempre gli stessi punti.
  • BitmapFactory.decodeResource: richiede molto tempo. Decodifica prima la bitmap, memorizzali e disegnali solo durante onDraw.
  • riciclare le bitmap quando non servono più, non ogni volta che li disegnato.

Per esempio:

  • decifrare il vostro bitmap durante onResume
  • riciclarli durante onPause
  • decodifica deve avvenire all'interno di un compito asincrona. Quando l'attività asincrona è finita, solleva una bandiera per indicare a onDraw che le immagini sono pronte e possono essere disegnate.
  • è molto importante decodificare le immagini in background in quanto richiede molto tempo. Non farlo nel thread principale dell'interfaccia utente. In caso contrario, la vostra applicazione sarà non risponde
  • calcolare il vostro screenPts all'interno onLayout e riutilizzare gli stessi punti per tutto il tempo.
  • non chiamare getIntent durante onDraw.

In breve, ridurre al minimo le operazioni durante onDraw e si otterrà un disegno molto veloce, circa 60 FPS.

Si dovrebbe anche prendere in considerazione la rimozione che l'interruttore (brutto) e utilizzare un HashMap per associare i valori di conteggio e la bitmap per disegnare. Un array sarebbe anche più veloce e forse più appropriato qui.

+0

puoi darmi un po 'di codice. perché non ne parlo più –

+4

@gaurav kumar Penso che la risposta sopra sia completa e non penso che sia richiesto alcun codice. Prima si cerca di capire il ciclo di vita delle attività, quindi si può facilmente applicare sopra le cose.Dovresti capire quante volte quale metodo e quando verrà chiamato. Quindi provare a riutilizzare il codice e utilizzare sempre thread o attività asincrone (consigliato in Android) per rimuovere il codice pesante dai thread dell'interfaccia utente e il gioco è fatto. Il concetto dato da "Snicolas" è molto generico e può essere applicato su tutte le piattaforme. –

Problemi correlati