2013-10-28 14 views
11

Próbuję narysować marker na pojedynczym kurkiem w systemie Android. kiedy narysuję znacznik, który narysuje, ale zajmie to więcej czasu, tj. 30-40 milisekund, czasami zajmuje to 2-3 sekundy. Oto mój kod dla klasy, w której mam metodę rysowania.Jak narysować bitmapę szybko w metodzie onDraw() w kanwie 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); 
     // } 
} 

Odpowiedz

18

Powinieneś zainicjować wszystkie bitmapy w Konstruktorze. Dekodowanie bitmapy zajmuje dużo czasu. Możesz użyć HashMap (klucz, wartość), aby je zapisać. Następnie w onDraw pobierz dopasowaną bitmapę i narysuj ją bezpośrednio.

Na przykład

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

Oto co zrobiłem na podstawie kodu. Musisz sprawdzić niektóre zduplikowane identyfikatory zasobów.

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

pozwól nam [kontynuować tę dyskusję na czacie] (http://chat.stackoverflow.com/rooms/40102/discussion-between-gaurav-kumar-and-yushulx) –

+0

Dzięki za udostępnienie kodu. Ale myślę, że nie potrzebujesz przełącznika w pierwszym przykładzie. Po prostu wykonaj to: 'int caller = getIntent(). GetIntExtra (" button ", 0); Bitmap bmp = mStore.get (wywołujący); canvas.drawBitmap (bmp, screenPts.x, screenPts.y - 50, null); bmp.recycle(); bmp = null; przerwa; } ' –

2

Należy usunąć wszystkie BitmapFactory.decodeResource() połączeń z metodą draw(). Odwzoruj bitmapę tylko raz i zachowaj odwołanie do niej. Następnie wystarczy zadzwonić pod numer canvas.drawBitmap() w swojej metodzie draw().

7

Ideą optymalizacji kodu jest wykonywanie tylko operacji niezbędnych do rysowania. Tak więc, powinieneś usunąć z swojej metody onDraw:

  • dowolne instanciation: zajmują dużo czasu, onDraw często jest wywoływany i nie chcesz tworzyć tylu nowych obiektów. Przechowuj screenPts podczas onLayout i zawsze używaj tych samych punktów.
  • BitmapFactory.decodeResource: zajmuje to dużo czasu. Najpierw dekoduj swoją bitmapę, przechowuj je i narysuj tylko podczas onDraw.
  • przetwarzaj mapy bitowe, gdy ich już nie potrzebujesz, nie za każdym razem, gdy je rysujesz.

Na przykład:

  • dekodowanie bitmap podczas onResume
  • recyklingu je podczas OnPause
  • dekodowania powinna nastąpić wewnątrz zadania asynchronicznym. Po zakończeniu zadania asynchronicznego należy podnieść flagę, aby wskazać onDraw, że obrazy są gotowe i można je narysować.
  • Bardzo ważne jest, aby dekodować obrazy w tle, ponieważ zajmuje to dużo czasu. Nie rób tego w głównym wątku UI. W przeciwnym razie Twoja aplikacja będzie wyglądała na nieodpowiedzialną
  • obliczyć swój screenPts wewnątrz onLayout i ponownie używać tych samych punktów przez cały czas.
  • nie wywołuj getIntent podczas pracy onDraw.

Krótko, zminimalizuj operacje podczas onDraw, a uzyskasz bardzo szybki rysunek, około 60 FPS.

Powinieneś także rozważyć usunięcie tego (brzydkiego) przełącznika i użycie hashmap do powiązania wartości count i bitmapy do narysowania. Tablica byłaby nawet szybsza i może bardziej odpowiednia tutaj.

+0

czy możesz podać mi kod. ponieważ nie przejmuję się tym. –

+4

@gaurav kumar Myślę, że powyższa odpowiedź jest kompletna i nie sądzę, że jakikolwiek kod jest wymagany. Najpierw próbujesz zrozumieć cykl życia aktywności, a następnie możesz łatwo zastosować powyższe rzeczy.Powinieneś wiedzieć, ile razy metoda i kiedy zostanie wywołana. Następnie spróbuj ponownie użyć swojego kodu i zawsze używaj wątków lub zadań asynchronicznych (zalecanych w systemie Android), aby usunąć ciężki kod z wątków interfejsu użytkownika i gotowe. Koncepcja podana przez "Snicolas" jest bardzo ogólna i może być stosowana na wszystkich platformach. –

Powiązane problemy