【问题标题】:Android Canvas Thread going crazyAndroid Canvas 线程发疯了
【发布时间】:2015-07-29 14:35:37
【问题描述】:

大家好:)我正在尝试使用我的 Mainthreat 在画布上进行绘制。 基本上我的目标是得到一个矩形,当我触摸它时它会改变颜色。 在 onCreate 方法中,我创建了矩形并调用 quadr1.setColor 方法来填充它。然后我开始威胁。现在 draw 方法应该只调用 quadr1.draw 方法,并用相同的颜色重新绘制矩形。当我触摸 quadr1 时,威胁现在再次调用 quadr1.setColor,而不是 quadr1.draw。这应该给它我的 RandomColor 类提供的新颜色(工作正常)。

现在的问题:当威胁正在运行时,画布只是消失以显示“背后的内容”并再次出现下一个动作。这看起来像是癫痫患者的一种折磨方法。我读到了双缓冲,但我自己找不到任何解决方案。如何让它显示填充稳定的矩形,并在我触摸它时改变?

public class GamePanel extends SurfaceView implements SurfaceHolder.Callback{

    private MainThread thread;
    private Canvas canvas;
    private Random random;
    private SurfaceHolder holder;
    RandomColor randomColor = new RandomColor();
    private boolean colorChangeTouchInput;

    private Quadr quadr1;

    public GamePanel(Context context){
        super(context);

        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        this.holder = holder;

        thread = new MainThread(holder);
        randomColor = new RandomColor();

        setFocusable(true);
    }

    class MainThread extends Thread{
        private boolean running;
        private SurfaceHolder surfaceHolder;

        public MainThread(SurfaceHolder surfaceHolder){
            this.surfaceHolder = surfaceHolder;
        }

        @Override
        public void run(){
            while(running) {
                canvas = null;
                try {
                    canvas = surfaceHolder.lockCanvas();
                    synchronized (surfaceHolder) {
                        if(colorChangeTouchInput=false) {
                            draw(canvas);
                        } else {
                            quadr1.setColor(canvas);
                        }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(canvas!= null){
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }

        private void draw(Canvas canvas) {
            quadr1.draw(canvas);
        }
        public void setRunning(boolean b) {
            running = b;
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder){
        boolean retry = true;
        int counter =0;
        while(retry && counter <1000) {

            counter++;
            try {
                thread.setRunning(false);
                thread.join();
                retry=false;

            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder){


        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int windowWidth = size.x;
        int windowHeight = size.y;

        canvas = null;
        canvas = holder.lockCanvas();

        quadr1 = new Quadr(0,0,windowWidth/2,windowHeight / 2, randomColor.getRandomColorA(), randomColor.getRandomColorR(), randomColor.getRandomColorG(), randomColor.getRandomColorB());
        quadr1.setColor(canvas);

        holder.unlockCanvasAndPost(canvas);

        thread.setRunning(true);
        thread.start();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        SurfaceHolder holderTouch = getHolder();

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                if(event.getX()>quadr1.getLeft() && event.getX()<quadr1.getRight() && event.getY()>quadr1.getTop() && event.getY()<quadr1.getBot()){
                    colorChangeTouchInput = true;  
                }             
        }      
        return super.onTouchEvent(event);
    }

    public boolean isColorChangeTouchInput() {
        return colorChangeTouchInput;
    }
}

这是我的 quadr 课程: (效果很好,还有 Random 颜色类,可以通过多种方式对其进行测试。)

public class Quadr extends GameObject {
    int left;
    int top;
    int right;
    int bot;
    int colorA[];
    int colorR[];
    int colorG[];
    int colorB[];
    int colorFixed;

    Paint paint = new Paint();
    Rect rect = new Rect();
    Random rnd = new Random();

    public Quadr(int left, int top, int right, int bottom, int colorA[], int colorR[], int colorG[], int colorB[]) {
        this.left=left;
        this.top=top;
        this.right=right;
        this.bot=bottom;
        this.colorA=colorA;
        this.colorR=colorR;
        this.colorG=colorG;
        this.colorB=colorB;

        rect.set(left, top, right, bottom);
    }

    public void setColor(Canvas canvas){
        int num = rnd.nextInt(3);
        colorFixed = num;

        paint.setStyle(Paint.Style.FILL);
    rnd.nextInt(256));
        paint.setARGB(colorA[num], colorR[num], colorG[num], colorB[num]);
        canvas.drawRect(rect, paint);
    }

    public void draw(Canvas canvas) {
        paint.setStyle(Paint.Style.FILL);
        paint.setARGB(colorA[colorFixed], colorR[colorFixed], colorG[colorFixed], colorB[colorFixed]);
        canvas.drawRect(rect, paint);

    }

    public int getLeft() {
        return left;
    }
    public int getTop() {
        return top;
    }
    public int getRight() {
        return right;
    }
    public int getBot() {
        return bot;
    }
}

非常感谢您的任何帮助!

【问题讨论】:

    标签: java android multithreading canvas callback


    【解决方案1】:

    据我所知,问题可能是由colorChangeTouchInput引起的。

    您在拦截触摸时将其设置为true,之后您再也不会将其设置为false。这将导致 draw() 方法永远不会在线程中被调用。我建议您在拨打quadr1.setColor(canvas); 之后添加colorChangeTouchInput = false

    【讨论】:

    • 没有解决我的问题,但谢谢!这是一个失误,因为我多次重建所有内容以找到解决方案:)
    • 另外,如果我可以添加一些建议:使用线程仅使表面视图无效,使用postInvalidate()。覆盖SurfaceView 中的onDraw() 方法并在那里执行实际绘图。这是一种更自然的方法,更适合使用画布的 Android 风格。不要忘记也调用setWillNotDraw(false) 以使视图能够自行绘制。希望这能帮助您轻松追踪您的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多