2013-08-13 3 views
0

다음 프로그램은 위치에 작은 구름별도의 스레드에서이 구체적인 예제를 그리는 데있어 잘못된 점은 무엇입니까?

cloud

에게 사용자의 터치를 그립니다.

/*A*////*A*/으로 바꾸면 정상적으로 실행됩니다.

그러나 부진합니다. 따라서 (/*A*/s을 주석 처리하지 않고) 드로잉은 별도의 스레드에서 수행됩니다. 원활한 상호 작용을 유지하기 위해 사용자가 포인터를 움직이면 스레드가 중단됩니다.

별도의 스레드에서 제대로 그릴 수 있도록이 코드를 어떻게 수정 하시겠습니까?

public class MyView extends View { 
/*A*/ protected MyDrawThread myDrawThread; 
    protected float x, y; 
    protected Paint paint = new Paint(); 

    public MyView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     paint.setAntiAlias(true); 
/*A*/ myDrawThread = new MyDrawThread(); 
    } 

    @Override protected void onDraw(Canvas canvas) 
    { 
/*A*/  if(myDrawThread.isAlive()) 
/*A*/   myDrawThread.interrupt(); 
/*A*/ 
/*A*/  myDrawThread.setCanvas(canvas); 
/*A*/  myDrawThread.start(); 
/*A*/ } 
/*A*/ 
/*A*/ class MyDrawThread extends Thread { 
/*A*/  private Canvas canvas; 
/*A*/ 
/*A*/  public MyDrawThread() { 
/*A*/   super(); 
/*A*/  } 
/*A*/  public void setCanvas(Canvas cnvs) { 
/*A*/   canvas = cnvs; 
/*A*/  } 
/*A*/  public void run() 
/*A*/  { 
      for(int i=0;i<10000;++i) { 
       double angle = (double) (Math.random() * 2.0 * Math.PI); 
       float distance = (float) (Math.random() * getWidth()/25.0f); 
       float dx = (float) (distance*Math.cos(angle)); 
       float dy = (float) (distance*Math.sin(angle)); 
       canvas.drawCircle(x+dx, y+dy, 0.1f, paint); 
      } 
/*A*/ } 
    } 
    @Override public boolean onTouchEvent(MotionEvent event) { 
     x = event.getX(); 
     y = event.getY(); 
     invalidate(); 
     return true; 
    } 
} 

레이아웃 activity_main

<.MyView 
    android:id="@+id/myView" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

구성과 활동은

당신은 할 수 없습니다
setContentView(R.layout.activity_main); 

답변

1

를 통해보기를 설정합니다. View.onDraw()으로 전달 된 Canvas은 기본 스레드 (UI 스레드)에서만 사용해야합니다. SurfaceView (임의 스레드에서 Canvas을 사용할 수 있음) 또는 TextureView (동일)을 사용하거나 중간 비트 맵으로 렌더링해야합니다.

+0

알 수 있습니다. SurfaceView에 대한 비슷한 질문을 던졌습니다. (드로잉이 너무 길어질 때 상호 작용을 유지하십시오.) http://stackoverflow.com/q/18240420/704972. – Calaf

1

이 경우 UI 스레드에서 그리기를 수행해야합니다. 또 다른 점은 드로잉은 onDraw() 내에서만 안전하게 수행 될 수 있다고 확신합니다. 긴 루프를 거치기 때문에 코드가 느립니다.

대신 이미지를 비트 맵으로 생성하는 별도의 스레드를 만듭니다. 그런 다음 비트 맵을 UI 스레드와 공유하면 실제로 비트 맵을 캔버스에 그릴 수 있습니다. lockstep 방식으로 작업을 가져 오기 위해 wait() 및 notify() 호출이 필요할 수도 있지만 다른 스레드에서 수행하는 데 너무 느려질 수 있습니다. 당신은 정말 동적, 나도

1) 만 UI마다 여러 프레임에 비트 맵을 업데이트,하지만 여전히 다른 스레드

2 이미지를 생성 할 수 있습니다) 다른를 사용한다고이 이미지를 확인하려면 여러 번 반복 할 필요가없는 이미지를 생성하는 방법

모범 사례에서, onDraw()는 가능한 한 빨리 수행해야하며 집중적 인 작업을 수행하지 않아야합니다.

+0

아이디어는 일부 장치에서 효과적으로 렌더링 할 수있는 것보다 그리기가 오래 걸리고 그 장치에서 사용자 이벤트가 그림을 선점하기를 원합니다.이 예제에서는 점 그림이 없으므로 사용자가 더 이상 관심이없는 입력입니다. – Calaf

+0

@Calaf 느린 장치에서도 작동하는 더 나은 솔루션은 5 개 정도의 이미지를 미리 생성 한 다음 드로잉 할 때 각 프레임 중 하나를 임의로 선택하는 것입니다. 많이 달라 보이지 않을 수도 있습니다. – user1132959

+0

긴 루프는 너무 오래 걸리는 도면을 시뮬레이션하는 방법 일뿐입니다. 대화식을 유지하기 위해 모든 사용자 이벤트에서 드로잉 중간 단계를 중단하고 싶습니다. 귀하의 답변에 감사드립니다. 이제 SurfaceView 컨텍스트에서 질문을했습니다 : http://stackoverflow.com/q/18240420/704972. – Calaf

관련 문제