Android 在方法中修改的变量不会在线程中更新
Android variable modified in method doesn't update in thread
我有一个简单的应用程序,它通过嵌套在 activity 布局中的 SurfaceView 在屏幕上显示图像。
我有一个 SurfaceViewExample class,它创建了一个新的 OurView 实例,并包含按钮调用的方法。共有三种方法:
- 第一个方法是arrowPressed(View view),当按下三个方向键中的任意一个时调用。它获取调用它的按钮的 ID 并将其传递给
- arrowAction(OurView ourview, String direction) 调用
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
我有一个简单的应用程序,它通过嵌套在 activity 布局中的 SurfaceView 在屏幕上显示图像。
我有一个 SurfaceViewExample class,它创建了一个新的 OurView 实例,并包含按钮调用的方法。共有三种方法:
- 第一个方法是arrowPressed(View view),当按下三个方向键中的任意一个时调用。它获取调用它的按钮的 ID 并将其传递给
- arrowAction(OurView ourview, String direction) 调用
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