在方法中修改的Android变量不会在线程中更新

时间:2015-04-06 16:09:45

标签: java android multithreading canvas scope

我有一个简单的应用程序,它通过嵌套在活动布局中的SurfaceView在屏幕上显示图像。

我有一个SurfaceViewExample类,它创建一个OurView的新实例,并包含按钮调用的方法。有三种方法:

  1. 第一种方法是arrowPressed(视图视图),当按下任意三个箭头键时调用该方法。它获取了哪个按钮的id,并将其传递给
  2. arrowAction(OurView myview,String direction)调用
  3. moveImage(int xChange,int yChange),在该方向上移动图像所需的x和y更改。

    public void arrowPressed(View view) {
        switch (view.getId()) {
    
            case R.id.arrowLeft:
                arrowAction(gameView, "left");
                break;
    
            case R.id.arrowRight:
                arrowAction(gameView, "right");
                break;
    
            case R.id.arrowUp:
                arrowAction(gameView, "up");
                break;
        }
    }
    
    ------------------------------------------------------------------------------------
    
    void arrowAction(OurView ourView, String direction) {
        switch (direction) {
    
            case "left":
                ourView.moveImage(-1,0);
                break;
    
            case "right":
                ourView.moveImage(1,0);
                break;
    
            case "up":
                ourView.moveImage(0,1);
                break;
        }
    }
    
    ------------------------------------------------------------------------------------
    
    void moveImage(int xChange, int yChange) {
        xCoord = xCoord + xChange;
        yCoord = yCoord + yChange;
    }
    
  4. 这一切似乎都按预期工作。 moveImage被成功调用,它修改了xCoord和yCoord变量。当我从moveImage中打印x和y Coords时,它们会反映其更改的值。但是,在moveImage中xCoord和yCoord以及线程MyThread中的xCoord和yCoord之间似乎存在脱节。

    方法doDraw(Canvas canvas)在(xPos,yPos)处绘制位图(这些变量只是调整了x和y Coords,以便图像以该坐标点为中心,而不是让它的左上角位于该坐标点上坐标点)。当我从这种方法打印x和y Coords时,它们会反映原始值。

    public void doDraw(Canvas canvas) {
        xPos = xCoord - (testimg.getWidth()/2);
        yPos = yCoord - (testimg.getHeight()/2);
        canvas.drawBitmap(testimg, xPos, yPos, null);
    }
    

    我能想到这一点的唯一原因是moveImage正在创建名为xCoord和yCoord的新局部变量。但是这没有意义,因为它成功获得了xCoord和yCoord的原始值。

    完整代码:

    SurfaceViewExample:

    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.os.Bundle;
    import android.util.AttributeSet;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    
    public class SurfaceViewExample extends Activity {
    
        OurView gameView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            gameView = new OurView(this);
            setContentView(R.layout.activity_surface_view_example);
        }
    
        public void arrowPressed(View view) {
            switch (view.getId()) {
    
                case R.id.arrowLeft:
                    arrowAction(gameView, "left");
                    break;
    
                case R.id.arrowRight:
                    arrowAction(gameView, "right");
                    break;
    
                case R.id.arrowUp:
                    arrowAction(gameView, "up");
                    break;
            }
        }
    
        void arrowAction(OurView ourView, String direction) {
            switch (direction) {
    
                case "left":
                    ourView.moveImage(-1,0);
                    break;
    
                case "right":
                    ourView.moveImage(1,0);
                    break;
    
                case "up":
                    ourView.moveImage(0,1);
                    break;
            }
        }
    }
    

    OurView:

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    
    public class OurView extends SurfaceView implements SurfaceHolder.Callback {
    
        private MyThread myThread;
        private SurfaceHolder holder;
        private Bitmap testimg;
        public int xCoord = 500;
        public int yCoord = 500;
        int xPos;
        int yPos;
    
        public OurView(Context context) {
            super(context);
            init();
        }
    
        public OurView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public OurView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        private void init() {
            myThread = new MyThread(this);
    
            holder = getHolder();
            holder.addCallback(this);
            testimg = BitmapFactory.decodeResource(getResources(),R.drawable.testimg);
        }
    
        void moveImage(int xChange, int yChange) {
            xCoord = xCoord + xChange;
            yCoord = yCoord + yChange;
            System.out.println("-----");
            System.out.println("-----");
            System.out.println(xCoord);
            System.out.println(yCoord);
            System.out.println("-----");
            System.out.println("-----");
        }
    
        public void doDraw(Canvas canvas) {
            System.out.println("Starting drawing...");
            System.out.println(xCoord);
            System.out.println(yCoord);
            xPos = xCoord - (testimg.getWidth()/2);
            yPos = yCoord - (testimg.getHeight()/2);
            System.out.println(xPos);
            System.out.println(yPos);
            canvas.drawBitmap(testimg, xPos, yPos, null);
            System.out.println("Drawing finished.");
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            myThread.setRunning(true);
            myThread.start();
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry =  true;
            myThread.setRunning(false);
    
            while (retry) {
                try {
                    myThread.join();
                    retry = false;
                }
    
                catch (InterruptedException e) {}
            }
        }
    
    }
    

    MyThread的:

    import android.graphics.Canvas;
    
    public class MyThread extends Thread{
    
        OurView myView;
        private boolean running = false;
    
        public MyThread(OurView view) {
            myView = view;
        }
    
        public void setRunning(boolean run) {
            running = run;
        }
    
        @Override
        public void run() {
            while(running){
    
                Canvas canvas = myView.getHolder().lockCanvas();
    
                if(canvas != null){
                    synchronized (myView.getHolder()) {
                        myView.doDraw(canvas);
                    }
                    myView.getHolder().unlockCanvasAndPost(canvas);
                }
    
                try {
                    sleep(30);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
            }
        }
    }
    

    MyThread类几乎是来自Create animation on SurfaceView in background Thread的纯副本+粘贴。

1 个答案:

答案 0 :(得分:0)

每次调用onDraw时,都会更改Canvas对象表单MyThread。您不应该在其他类中引用Canvas。