Android的SurfaceView帆布带拉线 [英] Android SurfaceView canvas drawing with a thread

查看:124
本文介绍了Android的SurfaceView帆布带拉线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用一个线程来创建一个简单的游戏引擎在画布上绘制,但我有一些奇怪的问题,我无法解释。 这种游戏的目的是要画一个圆每一秒在画布上。 这工作,但不是我想要的工作方式,似乎该应用程序在两个帆布之间切换,并添加了一圈每个画布等你拿每秒有圆圈的相同数量,但在不同的放置两个画布之间的开关在画布上。

我不知道我做错了,但我没那么熟悉Treadding,有什么事情跟我的Andr​​oid设备有多少个核拥有或类似的东西?

我的code如下图所示,所以我只用一个launchthread它使用layoutfile链接到该启动一个线程,并绘制一个圆形画布每一秒的animationthread。 (你可以忽略的TouchEvent,它没有使用过)。

该项目存在了主要launchthread的:

 公共类MainActivity延伸活动{

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.main);
    }
}
 

使用这种布局文件:

 < XML版本=1.0编码=UTF-8&GT?;
<的FrameLayout
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =FILL_PARENT>
        < com.androidtesting.AnimationView
            机器人:ID =@ + ID /诚挚的范例
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =FILL_PARENT/>
< /的FrameLayout>
 

和我有一个内螺纹类Surfaceview类:

 类AnimationView扩展了SurfaceView实现SurfaceHolder.Callback {
    私人布尔感动= FALSE;
    私人浮动touched_x,touched_y = 0;
    民营涂料粉刷;
    私人帆布℃;
    私人随机随机的;
    私人AnimationThread线;

    公共AnimationView(上下文的背景下,ATTRS的AttributeSet){
        超(背景下,ATTRS);

        SurfaceHolder支架= getHolder();
        holder.addCallback(本);

        螺纹=新AnimationThread(保持器);
    }

    类AnimationThread继承Thread {
        私人布尔mRun;
        私人SurfaceHolder mSurfaceHolder;

        公共AnimationThread(SurfaceHolder surfaceHolder){
            mSurfaceHolder = surfaceHolder;
            油漆=新的油漆();
            paint.setARGB(255255255255);
            paint.setTextSize(32);
        }

        @覆盖
        公共无效的run(){
            而(mRun){
                C = NULL;
                尝试 {
                    C = mSurfaceHolder.lockCanvas(空);
                    同步(mSurfaceHolder){
                        doDraw(C);
                        睡眠(1000);
                    }
                }赶上(例外五){
                    e.printStackTrace();
                }最后 {
                    如果(C!= NULL){
                        mSurfaceHolder.unlockCanvasAndPost(C);
                    }
                }
            }
        }

        私人无效doDraw(帆布油画){
            //清除画布
            //canvas.drawColor(Color.BLACK);

            随机=新的随机();
            INT W = canvas.getWidth();
            INT H = canvas.getHeight();
            INT X = random.nextInt(W-50);
            INT Y = random.nextInt(H-50);
            INT R = random.nextInt(255);
            INT G = random.nextInt(255);
            INT B = random.nextInt(255);
            INT大小= 20;
            canvas.drawCircle(X,Y,大小,油漆);
            canvas.restore();
        }
        公共无效setRunning(布尔B){
            mRun = B;
        }
    }

    公共无效surfaceChanged(SurfaceHolder持有人,INT格式,诠释的宽度,高度INT){

    }

    @覆盖
    公共布尔的onTouchEvent(MotionEvent事件){
           touched_x = event.getX();
           touched_y = event.getY();

           INT行动= event.getAction();

           开关(动作){
                案例MotionEvent.ACTION_DOWN:
                    感动= TRUE;
                    打破;
                案例MotionEvent.ACTION_MOVE:
                    感动= TRUE;
                    打破;
                默认:
                    感动= FALSE;
                    打破;
           }

           返回true;
    }

    公共无效surfaceCreated(SurfaceHolder持有者){
        thread.setRunning(真正的);
        thread.start();
    }

    公共无效surfaceDestroyed(SurfaceHolder持有者){
        布尔重试= TRUE;
        thread.setRunning(假);
        而(重试){
            尝试 {
                的Thread.join();
                重试= FALSE;
            }赶上(InterruptedException异常E){
            }
        }
    }
}
 

解决方案
  

似乎该应用程序在两个帆布

之间切换

是的,这是它的工作原理。这就是所谓的双缓冲,你需要重新绘制所有的帧每次

  

表面的内容从未$ unlockCanvas之间p $ pserved()和lockCanvas(),因为这个原因,在面积内的所有像素必须被写入。

所以,你需要这行 canvas.drawColor(Color.BLACK)来注释去掉,在code。

和你不应该叫视频下载(1000)画布时被锁定,这将导致的饥饿问题。

I am experimenting with drawing on a canvas using a thread to create a simple game engine but I'm having some weird issues I cannot explain. The purpose of this "game" is to draw a circle every second on the canvas. This works, but not the way I want it to work, it seems the app is switching between two canvasses and adding a circle to each canvas so you get a switch between two canvasses every second with the same number of circles but in a different place on the canvas.

I don't know what I'm doing wrong, but I'm not that familiar with Treadding, has it something to do with how many cores my android device has or something like that?

My code is shown below, so I just use a launchthread which uses a layoutfile that links to the animationthread which starts a thread and draws a circle on the canvas every second. (You can ignore the touchevent, it isn't uses yet).

The project exists out of a main launchthread:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

which uses this layout file:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">     
        <com.androidtesting.AnimationView
            android:id="@+id/aview"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
</FrameLayout>

And my Surfaceview class with an inner Thread class:

class AnimationView extends SurfaceView implements SurfaceHolder.Callback {
    private boolean touched = false;
    private float touched_x, touched_y = 0;
    private Paint paint;
    private Canvas c;
    private Random random;
    private AnimationThread thread;

    public AnimationView(Context context, AttributeSet attrs) {
        super(context, attrs);

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

        thread = new AnimationThread(holder);
    }

    class AnimationThread extends Thread {
        private boolean mRun;       
        private SurfaceHolder mSurfaceHolder;        

        public AnimationThread(SurfaceHolder surfaceHolder) {
            mSurfaceHolder = surfaceHolder;
            paint = new Paint();
            paint.setARGB(255,255,255,255);
            paint.setTextSize(32);
        }

        @Override
        public void run() {
            while (mRun) {
                c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {                 
                        doDraw(c);
                        sleep(1000);
                    }
                } catch (Exception e) {                 
                    e.printStackTrace();
                }finally {
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }

        private void doDraw(Canvas canvas) {
            //clear the canvas
            //canvas.drawColor(Color.BLACK);                        

            random = new Random();
            int w = canvas.getWidth();
            int h = canvas.getHeight();
            int x = random.nextInt(w-50); 
            int y = random.nextInt(h-50);
            int r = random.nextInt(255);
            int g = random.nextInt(255);
            int b = random.nextInt(255);
            int size = 20;
            canvas.drawCircle(x,y,size,paint);            
            canvas.restore();
        }
        public void setRunning(boolean b) {
            mRun = b;
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
           touched_x = event.getX();
           touched_y = event.getY();

           int action = event.getAction();

           switch(action){
                case MotionEvent.ACTION_DOWN:           
                    touched = true;
                    break;
                case MotionEvent.ACTION_MOVE:
                    touched = true;
                    break;        
                default:
                    touched = false;
                    break;
           }

           return true;
    }

    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        thread.setRunning(false);
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
}

解决方案

it seems the app is switching between two canvasses

Yes, this is how it works. It is called double buffering and you need to redraw all the frame each time:

The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written.

So you need this line canvas.drawColor(Color.BLACK) to be uncommented in your code.

And you shouldn't call Thread.sleep(1000) while canvas is locked, it will cause starvation issue.

这篇关于Android的SurfaceView帆布带拉线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆