2013-10-28 2 views
11

안드로이드에서 단일 탭 메서드로 표식을 그리려고합니다. 마커를 그릴 때 끌기는하지만 그리기에 더 많은 시간이 필요합니다. 즉 30-40 밀리 초가 걸리며 2 ~ 3 초가 걸립니다. 다음은 draw 메소드가있는 클래스의 코드입니다.캔버스 안드로이드에서 onDraw() 메서드로 비트 맵을 빠르게 그리는 방법

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 메소드에서 다음을 제거해야합니다.

  • 모든 인스턴스화 : 오랜 시간이 걸리고 onDraw는 자주 호출되며 너무 많은 새 객체를 만들고 싶지는 않습니다. onLayout 동안 screenPts를 저장하고 항상 동일한 점을 다시 사용하십시오.
  • BitmapFactory.decodeResource : 꽤 오랜 시간이 걸립니다. 먼저 비트 맵을 디코딩하고 저장 한 다음 onDraw 중에 그리십시오.
  • 비트 맵을 그리지 않을 때 더 이상 필요하지 않으면 비트 맵을 재활용하십시오. 예를 들어

:

  • 디코딩 비동기 작업을 내부에서 발생한다 onPause 동안을 재활용 onResume 동안 비트 맵을 디코딩. 비동기 작업이 끝나면 onDraw에 이미지를 준비하고 그릴 수 있음을 나타내는 플래그를 발생시킵니다.
  • 오랜 시간이 걸리므로 이미지를 배경으로 디코딩하는 것이 매우 중요합니다. 기본 UI 스레드에서는이 작업을 수행하지 마십시오. 그렇지 않으면 앱이 응답하지 않는 것처럼 보일 것입니다.
  • onLayout 내에서 screenPts를 계산하고 항상 같은 지점을 다시 사용하십시오.
  • onDraw 중에 getIntent를 호출하지 마십시오.

간단히 말해서 onDraw 동안 작업을 최소화하면 매우 빠른 드로잉, 약 60FPS를 얻을 수 있습니다.

또한 (못생긴) 스위치를 제거하고 해시 맵을 사용하여 count와 비트 맵 값을 연결하여 그릴 것을 고려해야합니다. 배열은 여기에서보다 빠르고 어쩌면 더 적절할 것입니다.

+0

나에게 몇 가지 코드를 제공 할 수 있습니까? 왜냐하면 나는 이걸 더 이상 접하지 않기 때문이야. –

+4

@ gaurav kumar 위의 대답은 완벽하다고 생각하지 않으며 모든 코드가 필요하다고 생각합니다. 먼저 활동 라이프 사이클을 이해하고 위의 사항을 쉽게 적용 할 수 있습니다.언제 어떤 방법으로 언제 호출 될지 이해해야합니다. 그런 다음 코드를 재사용하고 항상 스레드 또는 비동기 작업 (Android에서 권장)을 사용하여 UI 스레드에서 많은 코드를 제거하면 작업이 완료됩니다. "Snicolas"라는 개념은 매우 일반적이며 모든 플랫폼에 적용될 수 있습니다. –

관련 문제