这个具体的例子在单独的线程上绘制有什么问题?

时间:2013-08-13 17:06:29

标签: java android multithreading android-view

以下程序绘制了一个小云

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

2 个答案:

答案 0 :(得分:1)

你做不到。传递给Canvas的{​​{1}}只能在主线程(UI线程)中使用。您应该使用View.onDraw()(允许您使用任意SurfaceView线程),Canvas(相同的东西)或渲染到中间位图。

答案 1 :(得分:1)

在这种情况下,必须在UI线程上完成绘图。另一件事是我很确定绘图只能在onDraw()内部安全地完成。你的代码很慢,因为你经历了一个很长的循环。

因此,您将创建一个单独的线程,将该图像生成到Bitmap中。然后与UI线程共享该位图,您实际上可以将该位图绘制到画布上。您可能需要一组wait()和notify()调用来以锁步方式获取作业,但是,在另一个线程上执行此操作可能仍然太慢。如果你真的想让这个图像变得动态,我会

1)每隔几帧只更新UI上的位图,但你仍然可以用另一个线程生成图像

2)使用另一种方法生成不必循环多次的图像

在最佳实践中,你的onDraw()应该尽可能快,而不是做任何密集的工作。