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

Android variable modified in method doesn't update in thread

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

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

  1. 第一个方法是arrowPressed(View view),当按下三个方向键中的任意一个时调用。它获取调用它的按钮的 ID 并将其传递给
  2. arrowAction(OurView ourview, 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;
    }
    

这一切似乎都按预期工作。 moveImage 被成功调用,它修改了 xCoord 和 yCoord 变量。当我从 moveImage 中打印 x 和 y 坐标时,它们反映了它们改变的值。但是,moveImage中的xCoord和yCoord与线程MyThread中的xCoord和yCoord之间似乎存在脱节。

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

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 的原始值。

完整代码:

表面视图示例:

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

我们的看法:

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) {}
        }
    }

}

我的线程:

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 class 几乎是来自 Create animation on SurfaceView in background Thread 的纯复制粘贴。

每次调用 onDraw 时,Canvas 对象形式 MyThread 都会发生变化。您不应在其他 类.

中引用 Canvas