2013-10-28 70 views
11

我想在android中的單擊方法上繪製標記。當我畫出標記時,它會畫出來,但是畫出30-40毫秒需要更多的時間,有時需要2-3秒。這裏是我的繪圖方法的類的代碼。如何在canvas中的onDraw()方法中快速繪製位圖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); 
     // } 
} 

回答

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); Bitmap bmp = mStore.get(caller); canvas.drawBitmap(bmp,screenPts.x,screenPts.y - 50,null); bmp.recycle(); bmp = null; 休息; }' –

2

您應該從draw()方法中刪除所有BitmapFactory.decodeResource()來電。只解碼位圖一次並保持參考。然後在draw()方法中調用canvas.drawBitmap()

7

優化代碼的想法是僅執行繪製所需的操作。那麼,你應該從你的onDraw方法去除:

  • 任何instanciation:他們需要很長的時間,onDraw有通常被稱爲和你不希望創建許多新對象。在onLayout中存儲screenPts並始終重複使用相同的點。
  • BitmapFactory.decodeResource:這需要相當長的時間。首先解碼你的位圖,存儲它們並且只在onDraw中繪製它們。
  • 當您不再需要它們時,回收位圖,而不是每次提取它們。

例如:

  • 期間的onResume解碼你的位圖
  • 的onPause期間回收他們
  • 解碼應異步任務內發生。當異步任務結束時,提出一個標誌來指示onDraw圖像已準備就緒並可以繪製。
  • 解碼後臺圖像非常重要,因爲它需要很長時間。不要在主UI線程中執行此操作。否則你的應用程序看起來沒有反應
  • 在onLayout中計算你的screenPts並且一直重複使用相同的點。
  • 在onDraw中也不會調用getIntent。

簡而言之,儘量減少onDraw期間的操作,您將實現非常快速的繪製,大約60 FPS。

您還應該考慮刪除(醜陋)開關並使用散列圖關聯count和位圖的值來繪製。一個數組甚至可以更快,也許在這裏更合適。

+0

你可以給我一些代碼。因爲我沒有更多的抵制這一點。 –

+4

@gaurav kumar我認爲上述答案是完整的,不要以爲任何代碼是必需的。首先,您嘗試瞭解活動生命週期,然後您可以輕鬆應用以上的事情。你應該明白有多少次調用哪個方法以及何時調用。然後嘗試重用您的代碼,並始終使用線程或異步任務(在Android中推薦)從UI線程刪除繁重的代碼,然後完成。 「Snicolas」給出的概念非常通用,可以應用於所有平臺。 –