Android 绘制使用 SurfaceView 和 Thread
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10956583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android draw using SurfaceView and Thread
提问by Morten H?gseth
I am trying to draw a ball to my screen using 3 classes. I have read a little about this and I found a code snippet that works using the 3 classes on one page, Playing with graphics in Android
我正在尝试使用 3 个类在我的屏幕上绘制一个球。我已经阅读了一些关于这个的内容,我发现了一个代码片段,它可以在一个页面上使用 3 个类,在 Android 中玩图形
I altered the code so that I have a ball that is moving and shifts direction when hitting the wall like the picture below (this is using the code in the link).
我修改了代码,这样我的球在撞墙时会移动并改变方向,如下图所示(这是使用链接中的代码)。
Now I like to separate the classes into 3 different pages for not making everything so crowded, everything is set up the same way.
现在我喜欢将课程分成 3 个不同的页面,以免让一切变得如此拥挤,一切都以相同的方式设置。
Here are the 3 classes I have.
这是我拥有的 3 个课程。
- BallActivity.java
- Ball.java
- BallThread.java
- 球活动.java
- 球.java
- 球线程
package com.brick.breaker;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class BallActivity extends Activity {
private Ball ball;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
ball = new Ball(this);
setContentView(ball);
}
@Override
protected void onPause() {
super.onPause();
setContentView(null);
ball = null;
finish();
}
}
package com.brick.breaker;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class Ball extends SurfaceView implements SurfaceHolder.Callback {
private BallThread ballThread = null;
private Bitmap bitmap;
private float x, y;
private float vx, vy;
public Ball(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
x = 50.0f;
y = 50.0f;
vx = 10.0f;
vy = 10.0f;
getHolder().addCallback(this);
ballThread = new BallThread(getHolder(), this);
}
protected void onDraw(Canvas canvas) {
update(canvas);
canvas.drawBitmap(bitmap, x, y, null);
}
public void update(Canvas canvas) {
checkCollisions(canvas);
x += vx;
y += vy;
}
public void checkCollisions(Canvas canvas) {
if(x - vx < 0) {
vx = Math.abs(vx);
} else if(x + vx > canvas.getWidth() - getBitmapWidth()) {
vx = -Math.abs(vx);
}
if(y - vy < 0) {
vy = Math.abs(vy);
} else if(y + vy > canvas.getHeight() - getBitmapHeight()) {
vy = -Math.abs(vy);
}
}
public int getBitmapWidth() {
if(bitmap != null) {
return bitmap.getWidth();
} else {
return 0;
}
}
public int getBitmapHeight() {
if(bitmap != null) {
return bitmap.getHeight();
} else {
return 0;
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
ballThread.setRunnable(true);
ballThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
ballThread.setRunnable(false);
while(retry) {
try {
ballThread.join();
retry = false;
} catch(InterruptedException ie) {
//Try again and again and again
}
break;
}
ballThread = null;
}
}
package com.brick.breaker;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class BallThread extends Thread {
private SurfaceHolder sh;
private Ball ball;
private Canvas canvas;
private boolean run = false;
public BallThread(SurfaceHolder _holder,Ball _ball) {
sh = _holder;
ball = _ball;
}
public void setRunnable(boolean _run) {
run = _run;
}
public void run() {
while(run) {
canvas = null;
try {
canvas = sh.lockCanvas(null);
synchronized(sh) {
ball.onDraw(canvas);
}
} finally {
if(canvas != null) {
sh.unlockCanvasAndPost(canvas);
}
}
}
}
public Canvas getCanvas() {
if(canvas != null) {
return canvas;
} else {
return null;
}
}
}
Here is a picture that shows the outcome of these classes.
这是一张显示这些课程结果的图片。
I've tried to figure this out but since I am pretty new to Android development I thought I could ask for help.
我试图弄清楚这一点,但由于我对 Android 开发还很陌生,我想我可以寻求帮助。
Does any one know what is causing the ball to be draw like that? The code is pretty much the same as the one in the link and I have tried to experiment to find a solution but no luck.
有谁知道是什么导致球被拉成那样?该代码与链接中的代码几乎相同,我尝试尝试找到解决方案,但没有成功。
回答by android developer
well , as you can see on the image , you only drew the ball . instead , you need to re-drew a black background (or whatever that you wish) before each time you draw the ball.
好吧,正如您在图像上看到的,您只画了球。相反,您需要在每次绘制球之前重新绘制黑色背景(或您想要的任何背景)。
alternatively , you can draw a black area only on the previous position , but you might have problems with it later , when you use more objects.
或者,您可以只在前一个位置绘制一个黑色区域,但是以后使用更多对象时可能会出现问题。
here's a nice sample, similar to what you do
这是一个很好的示例,类似于您所做的
回答by Sorceri
A quick look and I would have to say you are just drawing on the same surface and never requesting your surfaceview to redraw itself. at the end of the finally block, in the IF Statement use: postInvalidate();
That should cause the surface view to redraw itself.
快速浏览一下,我不得不说你只是在同一个表面上绘图,从不要求你的表面视图重绘自己。在 finally 块的末尾,在 IF 语句中使用:postInvalidate();
这应该会导致表面视图重绘自身。
回答by wdog
put this
把这个
public void onDraw(Canvas canvas){
canvas.drawColor(Color.BLACK);
.....
}
回答by somenath mukhopadhyay
See how i have done the pendulum simulation at http://som-itsolutions.blogspot.in/2012/06/android-graphics-and-animation-pendulum.html
在http://som-itsolutions.blogspot.in/2012/06/android-graphics-and-animation-pendulum.html查看我是如何完成钟摆模拟的
You can clone the source code of this project from https://github.com/sommukhopadhyay/pendulumsimulation
你可以从https://github.com/sommukhopadhyay/pendulumsimulation克隆这个项目的源代码
回答by Dale Wilson
[edit]The answer was wrong, but the comment was helpful so I'll leave this answer up:
[编辑]答案是错误的,但评论很有帮助,所以我会留下这个答案:
Not the question you asked, but there is a problem in your code. In Android you are only allowed to write to the screen in the UI thread. This is the thread that runs all the Activity callbacks, etc. By writing to the screen from BallThread you are risking many odd failures in your program.
不是你问的问题,而是你的代码有问题。在 Android 中,您只能在 UI 线程中写入屏幕。这是运行所有活动回调等的线程。通过从 BallThread 写入屏幕,您将面临程序中许多奇怪的失败的风险。