SurfaceView实现双缓冲避免游戏闪屏
来源:互联网 发布:软件安装调试方案 编辑:程序博客网 时间:2024/06/06 05:34
双缓冲技术是游戏开发中的一个重要的技术,主要原理是:当一个动画争先显示时,程序又在改变它,前面还没有显示完,程序又请求重新绘制,这样屏幕就会不停地闪烁。而双驵冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上
双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。
本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
[1].[图片] 程序运行截图
[2].[代码] main.xml
01
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
02
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
03
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
04
android:orientation
=
"vertical"
>
05
06
<
LinearLayout
android:id
=
"@+id/LinearLayout01"
07
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
08
<
Button
android:id
=
"@+id/Button01"
android:layout_width
=
"wrap_content"
09
android:layout_height
=
"wrap_content"
android:text
=
"单个独立线程"
></
Button
>
10
<
Button
android:id
=
"@+id/Button02"
android:layout_width
=
"wrap_content"
11
android:layout_height
=
"wrap_content"
android:text
=
"两个独立线程"
></
Button
>
12
</
LinearLayout
>
13
<
SurfaceView
android:id
=
"@+id/SurfaceView01"
14
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
></
SurfaceView
>
15
</
LinearLayout
>
[3].[代码] TestSurfaceView.java
001
package
com.testSurfaceView;
002
003
import
java.lang.reflect.Field;
004
import
java.util.ArrayList;
005
import
android.app.Activity;
006
import
android.graphics.Bitmap;
007
import
android.graphics.BitmapFactory;
008
import
android.graphics.Canvas;
009
import
android.graphics.Paint;
010
import
android.graphics.Rect;
011
import
android.os.Bundle;
012
import
android.util.Log;
013
import
android.view.SurfaceHolder;
014
import
android.view.SurfaceView;
015
import
android.view.View;
016
import
android.widget.Button;
017
018
public
class
TestSurfaceView
extends
Activity {
019
/** Called when the activity is first created. */
020
Button btnSingleThread, btnDoubleThread;
021
SurfaceView sfv;
022
SurfaceHolder sfh;
023
ArrayList<Integer> imgList =
new
ArrayList<Integer>();
024
int
imgWidth, imgHeight;
025
Bitmap bitmap;
//独立线程读取,独立线程绘图
026
027
@Override
028
public
void
onCreate(Bundle savedInstanceState) {
029
super
.onCreate(savedInstanceState);
030
setContentView(R.layout.main);
031
032
btnSingleThread = (Button)
this
.findViewById(R.id.Button01);
033
btnDoubleThread = (Button)
this
.findViewById(R.id.Button02);
034
btnSingleThread.setOnClickListener(
new
ClickEvent());
035
btnDoubleThread.setOnClickListener(
new
ClickEvent());
036
sfv = (SurfaceView)
this
.findViewById(R.id.SurfaceView01);
037
sfh = sfv.getHolder();
038
sfh.addCallback(
new
MyCallBack());
// 自动运行surfaceCreated以及surfaceChanged
039
}
040
041
class
ClickEvent
implements
View.OnClickListener {
042
043
@Override
044
public
void
onClick(View v) {
045
046
if
(v == btnSingleThread) {
047
new
Load_DrawImage(
0
,
0
).start();
//开一条线程读取并绘图
048
}
else
if
(v == btnDoubleThread) {
049
new
LoadImage().start();
//开一条线程读取
050
new
DrawImage(imgWidth +
10
,
0
).start();
//开一条线程绘图
051
}
052
053
}
054
055
}
056
057
class
MyCallBack
implements
SurfaceHolder.Callback {
058
059
@Override
060
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
061
int
height) {
062
Log.i(
"Surface:"
,
"Change"
);
063
064
}
065
066
@Override
067
public
void
surfaceCreated(SurfaceHolder holder) {
068
Log.i(
"Surface:"
,
"Create"
);
069
070
// 用反射机制来获取资源中的图片ID和尺寸
071
Field[] fields = R.drawable.
class
.getDeclaredFields();
072
for
(Field field : fields) {
073
if
(!
"icon"
.equals(field.getName()))
// 除了icon之外的图片
074
{
075
int
index =
0
;
076
try
{
077
index = field.getInt(R.drawable.
class
);
078
}
catch
(IllegalArgumentException e) {
079
// TODO Auto-generated catch block
080
e.printStackTrace();
081
}
catch
(IllegalAccessException e) {
082
// TODO Auto-generated catch block
083
e.printStackTrace();
084
}
085
// 保存图片ID
086
imgList.add(index);
087
}
088
}
089
// 取得图像大小
090
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
091
imgList.get(
0
));
092
imgWidth = bmImg.getWidth();
093
imgHeight = bmImg.getHeight();
094
}
095
096
@Override
097
public
void
surfaceDestroyed(SurfaceHolder holder) {
098
Log.i(
"Surface:"
,
"Destroy"
);
099
100
}
101
102
}
103
104
/**
105
* 读取并显示图片的线程
106
*/
107
class
Load_DrawImage
extends
Thread {
108
int
x, y;
109
int
imgIndex =
0
;
110
111
public
Load_DrawImage(
int
x,
int
y) {
112
this
.x = x;
113
this
.y = y;
114
}
115
116
public
void
run() {
117
while
(
true
) {
118
Canvas c = sfh.lockCanvas(
new
Rect(
this
.x,
this
.y,
this
.x
119
+ imgWidth,
this
.y + imgHeight));
120
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
121
imgList.get(imgIndex));
122
c.drawBitmap(bmImg,
this
.x,
this
.y,
new
Paint());
123
imgIndex++;
124
if
(imgIndex == imgList.size())
125
imgIndex =
0
;
126
127
sfh.unlockCanvasAndPost(c);
// 更新屏幕显示内容
128
}
129
}
130
};
131
132
/**
133
* 只负责绘图的线程
134
*/
135
class
DrawImage
extends
Thread {
136
int
x, y;
137
138
public
DrawImage(
int
x,
int
y) {
139
this
.x = x;
140
this
.y = y;
141
}
142
143
public
void
run() {
144
while
(
true
) {
145
if
(bitmap !=
null
) {
//如果图像有效
146
Canvas c = sfh.lockCanvas(
new
Rect(
this
.x,
this
.y,
this
.x
147
+ imgWidth,
this
.y + imgHeight));
148
149
c.drawBitmap(bitmap,
this
.x,
this
.y,
new
Paint());
150
151
sfh.unlockCanvasAndPost(c);
// 更新屏幕显示内容
152
}
153
}
154
}
155
};
156
157
/**
158
* 只负责读取图片的线程
159
*/
160
class
LoadImage
extends
Thread {
161
int
imgIndex =
0
;
162
163
public
void
run() {
164
while
(
true
) {
165
bitmap = BitmapFactory.decodeResource(getResources(),
166
imgList.get(imgIndex));
167
imgIndex++;
168
if
(imgIndex == imgList.size())
//如果到尽头则重新读取
169
imgIndex =
0
;
170
}
171
}
172
};
173
}
0 0
- SurfaceView实现双缓冲避免游戏闪屏
- SurfaceView双缓冲应用(心电图绘制),避免闪烁
- SurfaceView双缓冲
- SurfaceView双缓冲Demo
- SurfaceView 双缓冲应用
- SurfaceView 双缓冲应用
- SurfaceView双缓冲Demo
- SurfaceView双缓冲测试
- 定时通知(Notification)刷新实现SurfaceView双缓冲机制
- 定时通知(Notification)刷新实现SurfaceView双缓冲机制
- 双缓冲绘图与SurfaceView(二):SurfaceView
- 双缓冲避免闪烁
- Android SurfaceView 双缓冲机制
- surfaceview 双缓冲的理解
- Android SurfaceView双缓冲绘图
- SurfaceView的双缓冲机制
- Android SurfaceView双缓冲绘图
- Android surfaceview双缓冲机制和闪屏的解决方法内附代码详解
- 黑马程序员--基础加强--第四篇--继承Thread类和实现Runnable接口有什么区别?
- Python Unittest源码分析
- PC机交叉编译ARM boost库
- POJ 3177 Redundant Paths / 边双连通分量
- 微信服务号VS订阅号
- SurfaceView实现双缓冲避免游戏闪屏
- C++中的const
- Deployment failure on Tomcat 6.x. Could not copy all resources...
- 程序猿起步篇
- 修改AXD编辑状态下字体大小方法
- hibernate-02-17
- 九度OJ 1408 吃豆机器人 -- 动态规划
- PKU 2752
- cocos2d-x 2.2.2 环境配置和创建工程的一些问题