求android求ps大神帮忙p图,帮忙看懂一个surfaceview的代码项目

Android 的 SurfaceView 双缓冲应用 - 开源中国社区
当前访客身份:游客 [
当前位置:
发布于 日 21时,
双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。
本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
代码片段(3)
1.&[图片] 程序运行截图&&&&
2.&[代码]main.xml&&&&
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical"&
&LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="wrap_content" android:layout_height="wrap_content"&
&Button android:id="@+id/Button01" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="单个独立线程"&&/Button&
&Button android:id="@+id/Button02" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="两个独立线程"&&/Button&
&/LinearLayout&
&SurfaceView android:id="@+id/SurfaceView01"
android:layout_width="fill_parent" android:layout_height="fill_parent"&&/SurfaceView&
&/LinearLayout&
3.&[代码]TestSurfaceView.java&&&&
package com.testSurfaceV
import java.lang.reflect.F
import java.util.ArrayL
import android.app.A
import android.graphics.B
import android.graphics.BitmapF
import android.graphics.C
import android.graphics.P
import android.graphics.R
import android.os.B
import android.util.L
import android.view.SurfaceH
import android.view.SurfaceV
import android.view.V
import android.widget.B
public class TestSurfaceView extends Activity {
/** Called when the activity is first created. */
Button btnSingleThread, btnDoubleT
ArrayList&Integer& imgList = new ArrayList&Integer&();
int imgWidth, imgH
B//独立线程读取,独立线程绘图
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSingleThread = (Button) this.findViewById(R.id.Button01);
btnDoubleThread = (Button) this.findViewById(R.id.Button02);
btnSingleThread.setOnClickListener(new ClickEvent());
btnDoubleThread.setOnClickListener(new ClickEvent());
sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);
sfh = sfv.getHolder();
sfh.addCallback(new MyCallBack());// 自动运行surfaceCreated以及surfaceChanged
class ClickEvent implements View.OnClickListener {
public void onClick(View v) {
if (v == btnSingleThread) {
new Load_DrawImage(0, 0).start();//开一条线程读取并绘图
} else if (v == btnDoubleThread) {
new LoadImage().start();//开一条线程读取
new DrawImage(imgWidth + 10, 0).start();//开一条线程绘图
class MyCallBack implements SurfaceHolder.Callback {
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.i("Surface:", "Change");
public void surfaceCreated(SurfaceHolder holder) {
Log.i("Surface:", "Create");
// 用反射机制来获取资源中的图片ID和尺寸
Field[] fields = R.drawable.class.getDeclaredFields();
for (Field field : fields) {
if (!"icon".equals(field.getName()))// 除了icon之外的图片
int index = 0;
index = field.getInt(R.drawable.class);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// 保存图片ID
imgList.add(index);
// 取得图像大小
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(0));
imgWidth = bmImg.getWidth();
imgHeight = bmImg.getHeight();
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("Surface:", "Destroy");
* 读取并显示图片的线程
class Load_DrawImage extends Thread {
int imgIndex = 0;
public Load_DrawImage(int x, int y) {
public void run() {
while (true) {
Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x
+ imgWidth, this.y + imgHeight));
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
c.drawBitmap(bmImg, this.x, this.y, new Paint());
imgIndex++;
if (imgIndex == imgList.size())
imgIndex = 0;
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
* 只负责绘图的线程
class DrawImage extends Thread {
public DrawImage(int x, int y) {
public void run() {
while (true) {
if (bitmap != null) {//如果图像有效
Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x
+ imgWidth, this.y + imgHeight));
c.drawBitmap(bitmap, this.x, this.y, new Paint());
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
* 只负责读取图片的线程
class LoadImage extends Thread {
int imgIndex = 0;
public void run() {
while (true) {
bitmap = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
imgIndex++;
if (imgIndex == imgList.size())//如果到尽头则重新读取
imgIndex = 0;
开源中国-程序员在线工具:
相关的代码(404)
28回/113775阅
124回/91979阅
11回/86776阅
58回/79853阅
76回/78859阅
56回/58686阅
25回/52947阅
19回/48799阅
4回/45161阅
19回/44054阅
能否在实现全屏FLASH播放?
2楼:子旺 发表于
有没有可能预处理线程 &处理了几张图片,但是画图的线程还在画第一张那样的 情况呢
3楼:snowdream 发表于
受益匪浅,感谢分享。
有几个问题想咨询楼主:
1、LoadImage函数中bitmap = BitmapFactory.decodeResource(getResources(),imgList.get(imgIndex));
bitmap应该是申请内存了吧。是否需要释放,在哪里释放?
2、LoadImage和DrawImage函数时两个独立的线程,两者共有资源是bitmap。会不会出现这种情况:
LoadImage正在画bitmap,而DrawImage也正在帖DrawImage?
要不要用synchronized对bitmap进行处理呢?
3、如楼上所说,会不会出现LoadImage已经处理了好几张图片,而DrawImage才画其中一张,造成有图片丢失,没画出来呢?
4楼:单链DNA 发表于
由于是共用同一组图片,这样对比应该不准确吧。
5楼:dclchj 发表于
谢谢分享!以上问题确实需要考虑,不过LZ本文目的为了说明双缓冲的应用,所以我觉得尽量简单是合理的。
6楼:OrionBox 发表于
问下,如何截取动态图片??
7楼:沈在宏 发表于
求demo& 大侠&
8楼:南寒之星 发表于
把工程也发出了吧
9楼:张师傅 发表于
工程源码我共享了/file/anglish/0d045c88/
10楼:邱胜 发表于
感谢分享啊,哈哈
11楼:那都不是事児 发表于
谢谢分享,受益匪浅
12楼:icanfly 发表于
引用来自“子旺”的评论有没有可能预处理线程 &处理了几张图片,但是画图的线程还在画第一张那样的 情况呢我觉得完全有可能的,我看了楼主的代码,发现BitMap bitmap是在两个线程中共用的,楼主没有注意线程安全问题。
13楼:侯冠文 发表于
您好,这行代码&if(imgIndex == imgList.size())出现错误提示,提示是:没有为类型Field定义方法size()。 请问怎么解决?
14楼:小ping 发表于
坑爹的 报错了
开源从代码分享开始
鉴客的其它代码android 基于surfaceview 的多点触控实现 - fokman - ITeye技术网站
博客分类:
hello,各位朋友。最近接到一个功能需要实现多点触控,也就是我们通常所看到的把手指放在屏幕上,可以放大和缩小图片的 操作。在google上查找了一些资料,发现很多都是使用imageView在实现的。但是在游戏的开发过程中,使用surfaceview效率会更高一些,所以就尝试使用surfaceview来实现。
public class DisplayActivity extends Activity {
private SurfaceView videoV
private SurfaceH
private boolean flag =
private int screenW, screenH;
private Bitmap bmpI
//记录两个触屏点的坐标
private int x1, x2, y1, y2;
private float rate = 1;
//记录上次的????
private float oldRate = 1;
//记录第一次触屏时线段的长??
private float oldLineD
//判定是否头次多指触点屏幕
private boolean isFirst =
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.media_play);
videoView = (SurfaceView)findViewById(R.id.videoView);
sfh = videoView.getHolder();
sfh.addCallback(new DisplaySurfaceView());
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
screenW = dm.widthP
screenH = (dm.heightPixels)/2;
class DisplaySurfaceView implements SurfaceHolder.Callback{
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
public void surfaceCreated(SurfaceHolder arg0) {
new ImageThread().start();
public void surfaceDestroyed(SurfaceHolder arg0) {
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (event.getPointerCount() & 1) {
x1 = (int) event.getX(0);
y1 = (int) event.getY(0);
x2 = (int) event.getX(1);
y2 = (int) event.getY(1);
if (event.getPointerCount() == 2) {
if (isFirst) {
//得到第一次触屏时线段的长??
oldLineDistance = (float) Math.sqrt(Math.pow(event.getX(1) - event.getX(0), 2) + Math.pow(event.getY(1) - event.getY(0), 2));
//得到非第????触屏时线段的长度
float newLineDistance = (float) Math.sqrt(Math.pow(event.getX(1) - event.getX(0), 2) + Math.pow(event.getY(1) - event.getY(0), 2));
//获取本次的缩放比??
rate = oldRate * newLineDistance / oldLineD
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
class ImageThread extends Thread{
public void run() {
while (flag) {
long start = System.currentTimeMillis();
long end = System.currentTimeMillis();
if (end - start & 50) {
Thread.sleep(50 - (end - start));
} catch (InterruptedException e) {
e.printStackTrace();
public void myDraw() {
canvas = sfh.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.BLACK);
canvas.save();
//缩放画布(以图片中心点进行缩放,XY轴缩放比例相??
bmpIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.aa);
canvas.scale(rate, rate, screenW / 2, screenH / 2);
int width = screenW / 2 - bmpIcon.getWidth() / 2;
int height = screenH / 2 - bmpIcon.getHeight() / 2;
//绘制位图icon
canvas.drawBitmap(bmpIcon, width, height, paint);
canvas.restore();
//便于观察,这里绘制两个触点时形成的线??
canvas.drawLine(x1, y1, x2, y2, paint);
sfh.unlockCanvasAndPost(canvas);
} catch (Exception e) {
e.printStackTrace();
} finally {
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
media_play.xml
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" &
android:id="@+id/displayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text=""
android:textColor="#AA1122" /&
&LinearLayout
android:layout_width="fill_parent"
android:layout_height="400dp" &
&SurfaceView
android:id="@+id/videoView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="matrix" /&
&/LinearLayout&
android:id="@+id/aaaBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="123321" /&
&/LinearLayout&
这样就实现了多点触控,放大和缩小图片的效果了,aa这个图片是自己随便找的一个,可以根据实际情况修改。
浏览: 146637 次
来自: 武汉
如果用Ribbon控件来实现导航,都不需要这些代码
大神,着tcp/ip 长连接怎么实现
android基于netty的发送图片与文字demo,楼主共勉 ...
学习了,谢谢分享
请问大神:可以将这个Android的源码发给我吗,邮箱是:35 ...程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Android研究院之游戏开发View与SurFaceView的区别(五)
Android研究院之游戏开发View与SurFaceView的区别(五)
围观13410次
编辑日期: 字体:
view在api中的结构
java.lang.Object
android.view.View
直接子类:
AnalogClock, ImageView, KeyboardView, ProgressBar, SurfaceView, TextVie, ViewGroup, ViewStub
间接子类:
AbsListView, AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView&T extends Adapter&, AppWidgetHostView, AutoCompleteTextView, Button, CheckBox, CheckedTextView, Chronometer, CompoundButton, DatePicker, DialerFilter, DigitalClock,EditView, ExpandableListView, ExtractEditText, FrameLayout, GLSurfaceView, Gallery, GestureOverlayView, GridView, HorizontalScrollView, ImageButton, ImageSwitcher, LinearLayout, ListView, MediaController, MultiAutoCompleteTextView, QuickContactBadge, RadioButton, RadioGroup, RatingBar, RelativeLayout, ScrollView, SeekBar, SlidingDrawer, Spinner, TabHost, TabWidget, TableLayout, TableRow, TextSwitcher, TimePicker, ToggleButton, TwoLineListItem, VideoView, ViewAnimator, ViewFlipper, ViewSwitcher, WebView, ZoomButton, ZoomControls
由此可见View类属于Android开发绘制中的显示老大,任何与绘制有关系的控件都是它的子类。在这篇文章中我主要讲View 与SurFaceView 使用线程刷新屏幕绘制方面的知识。开发中如何去选择使用View还是SurFaceView。我相信读过我前几篇博客的朋友应该知道我在刷新屏幕的时候使用invalidate()方法来重绘,下面我详细的说明一下Andooid刷新屏幕的几种方法。
第一种: 在onDraw方法最后调用invalidate()方法,它会通知UI线程重绘 这样 View会重新调用onDraw方法,实现刷新屏幕。 这样写看起来代码非常简洁漂亮,但是它也同时存在一个很大的问题,它和游戏主线程是分开的 它违背了单线程模式,这样操作绘制的话是很不安全的,举个例子 比如程序先进在Activity1中 使用invalidate()方法来重绘, 然后我跳到了Activity2这时候Activity1已经finash()掉 可是Activity1中 的invalidate() 的线程还在程序中,Android的虚拟机不可能主动杀死正在运行中的线程所以这样操作是非常危险的。因为它是在UI线程中被动掉用的所以很不安全。
invalidate()
更新整个屏幕区域
invalidate(Rect rect) 更新Rect区域
invalidate(l, t, r, b) 更新指定矩形区域
&&&&public void onDraw(Canvas canvas){&&&&&&&&&&&&DosomeThing();&&&&&&&&&&&&invalidate();&&&&}
第二种:使用postInvalidate();方法来刷新屏幕 ,调用后它会用handler通知UI线程重绘屏幕,我们可以 new
Thread(this).start(); 开启一个游戏的主线程 然后在主线程中通过调用postInvalidate();方法来刷新屏幕。postInvalidate();方法 调用后 系统会帮我们调用onDraw方法 ,它是在我们自己的线程中调用 通过调用它可以通知UI线程刷新屏幕 。由此可见它是主动调用UI线程的。所以建议使用postInvalidate()方法通知UI线程来刷新整个屏幕。
postInvalidate(left, top, right, bottom) 方法 通过UI线程来刷新规定矩形区域。
123456789101112
@Override public void run() { &&&&while (mIsRunning) {
&&&&Thread.sleep(100);&&&&&&&&&&&&&&&&&&&&postInvalidate();
} catch (InterruptedException e) {
&&&&// TODO Auto-generated catch block
&&&&e.printStackTrace();
View中用到的双缓冲技术
重绘的原理是 程序根据时间来刷新屏幕 如果有一帧图形还没有完全绘制结束 程序就开始刷新屏幕这样就会造成瞬间屏幕闪烁 画面很不美观,所以双缓冲的技术就诞生了。它存在的目的就是解决屏幕闪烁的问题,下面我说说在自定义View中如何实现双缓冲。
首先我们需要创建一张屏幕大小的缓冲图片,我说一下第三个参数 ARGB 分别代表的是 透明度
Bitmap.Config
分别占四位
Bitmap.Config
分别占八位
Bitmap.Config
没有透明度(A)
一般情况下我们使用ARGB_8888 因为它的效果是最好了 当然它也是最占内存的。
&& mBufferBitmap = Bitmap.createBitmap(mScreenWidth,mScreenHeight,Config.ARGB_8888);
创建一个缓冲的画布,将内容绘制在缓冲区mBufferBitmap中
Canvas mCanvas = new Canvas(); mCanvas.setBitmap(mBufferBitmap);
最后一次性的把缓冲区mBufferBitmap绘制在屏幕上,怎么样 简单吧 呵呵。
12345678910111213141516171819202122232425
@Override protected void onDraw(Canvas canvas) { &&&&/**这里先把所有须要绘制的资源绘制到mBufferBitmap上**/ &&&&/**绘制地图**/ &&&&DrawMap(mCanvas,mPaint,mBitmap); &&&&/**绘制动画**/ &&&&RenderAnimation(mCanvas); &&&&/**更新动画**/ &&&&UpdateAnimation();& &&&&if(isBorderCollision) {
DrawCollision(mCanvas,"与边界发生碰撞"); &&&&}& &&&&if(isAcotrCollision) {
DrawCollision(mCanvas,"与实体层发生碰撞"); &&&&} &&&&if(isPersonCollision) {
DrawCollision(mCanvas,"与NPC发生碰撞"); &&&&}& &&&&/**最后通过canvas一次性的把mBufferBitmap绘制到屏幕上**/ &&&&canvas.drawBitmap(mBufferBitmap, 0,0, mPaint); &&&&super.onDraw(canvas); }
由此可见view属于被动刷新, 因为我们做的任何刷新的操作实际上都是通知UI线程去刷新。所以在做一些只有通过玩家操作以后才会刷新屏幕的游戏 并非自动刷新的游戏 可以使用view来操作。
2.SurfaceView
从API中可以看出SurfaceView属于View的子类 它是专门为制作游戏而产生的,它的功能非常强大,最重要的是它支持OpenGL ES库,2D和3D的效果都可以实现。创建SurfaceView的时候需要实现SurfaceHolder.Callback接口,它可以用来监听SurfaceView的状态,SurfaceView的改变 SurfaceView的创建 SurfaceView 销毁
我们可以在相应的方法中做一些比如初始化的操作 或者 清空的操作等等。
使用SurfaceView构建游戏框架它的绘制原理是绘制前先锁定画布 然后等都绘制结束以后 在对画布进行解锁 最后在把画布内容显示到屏幕上。
代码中是如何实现SurfaceView
首先需要实现 Callback 接口 与Runnable接口
public class AnimView extends SurfaceView implements Callback,Runnable
获取当前mSurfaceHolder 并且把它加到CallBack回调函数中
&&&&SurfaceHolder&&mSurfaceHolder = getHolder(); &&&&mSurfaceHolder.addCallback(this);
通过callBack接口监听SurfaceView的状态, 在它被创建的时候开启游戏的主线程,结束的时候销毁。这里说一下在View的构造函数中是拿不到view有关的任何信息的,因为它还没有构建好。 所以通过这个监听我们可以在surfaceCreated()中拿到当前view的属性 比如view的宽高 等等,所以callBack接口还是非常有用处的。
1234567891011121314151617181920
@Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) { &&&&// surfaceView的大小发生改变的时候& }& @Override public void surfaceCreated(SurfaceHolder arg0) { &&&&/**启动游戏主线程**/ &&&&mIsRunning = true; &&&&mThread = new Thread(this); &&&&mThread.start(); }& @Override public void surfaceDestroyed(SurfaceHolder arg0) {
// surfaceView销毁的时候 &&&&mIsRunning = false; }
在游戏主线程循环中在绘制开始 先拿到画布canvas 并使用mSurfaceHolder.lockCanvas()锁定画布,等绘制结束以后 使用mSurfaceHolder.unlockCanvasAndPost(mCanvas)解锁画布,
解锁画布以后画布上的内容才会显示到屏幕上。
1234567891011121314151617181920
@Override public void run() { &&&&while (mIsRunning) {
&&&&Thread.sleep(100);
} catch (InterruptedException e) {
&&&&// TODO Auto-generated catch block
&&&&e.printStackTrace();
//在这里加上线程安全锁
synchronized (mSurfaceHolder) {
&&&&/**拿到当前画布 然后锁定**/
&&&&mCanvas =mSurfaceHolder.lockCanvas();
&&&&Draw();
&&&&/**绘制结束后解锁显示在屏幕上**/
&&&&mSurfaceHolder.unlockCanvasAndPost(mCanvas);
由此可见SurfaceView 属于主动刷新 ,重绘过程完全是在我们自己的线程中完成 , 由于游戏中肯定会执行各种绚丽的动画效果如果使用被动刷新的View就有可能就会阻塞UI线程,所以SurfaceView 更适合做游戏。
最近有朋友反映说运行起来有点卡 我解释一下,
卡的主要原因是我的地图文件太大了,当然还有模拟器不给力的原因。我每绘制一块地图就须要使用裁剪原图,频繁的切割如此大的图片肯定会造成卡顿的情况。同学们在制作的时候将没用的地图块去掉,保留只需要的地图块这样会流畅很多喔 。
优化游戏主线程循环
同学们先看看这段代码,Draw()方法绘制结束让线程等待100毫秒在进入下一次循环。其实这样更新游戏循环是很不科学的,原因是Draw()方法每一次更新所耗费的时间是不确定的。举个例子 比如第一次循环Draw() 耗费了1000毫秒 加上线程等待100毫秒 整个循环耗时1100毫秒,第二次循环Draw() 耗时2000毫秒 加上线程等待时间100毫秒 整个循环时间就是2100毫秒。很明显这样就会造成游戏运行刷新时间时快时慢,所以说它是很不科学的。
1234567891011121314151617
public void run() { &&&&while (mIsRunning) {
//在这里加上线程安全锁
synchronized (mSurfaceHolder) {
&&&&/**拿到当前画布 然后锁定**/
&&&&mCanvas =mSurfaceHolder.lockCanvas();
&&&&Draw();
&&&&/**绘制结束后解锁显示在屏幕上**/
&&&&mSurfaceHolder.unlockCanvasAndPost(mCanvas);
&&&&Thread.sleep(100);
} catch (InterruptedException e) {
&&&&e.printStackTrace();
在贴一段科学的控游戏制循环代码,每次循环游戏主线程 在Draw()方法前后计算出Draw()方法所消耗的时间,然后在判断是否达到我们规定的刷新屏幕时间,下例是以30帧刷新一次屏幕,如果满足则继续下次循环如果不满足使用Thread.yield(); 让游戏主线程去等待 并计算当前等待时间直到等待时间满足30帧为止在继续下一次循环刷新游戏屏幕。
这里说一下Thread.yield(): 与Thread.sleep(long millis):的区别,Thread.yield(): 是暂停当前正在执行的线程对象 ,并去执行其他线程。Thread.sleep(long millis):则是使当前线程暂停参数中所指定的毫秒数然后在继续执行线程。
123456789101112131415161718192021222324252627282930313233
&&&&&&&&/**每30帧刷新一次屏幕**/&&&&&&&&public static final int TIME_IN_FRAME = 30; @Override public void run() { &&&&while (mIsRunning) {&
/**取得更新游戏之前的时间**/
long startTime = System.currentTimeMillis();&
/**在这里加上线程安全锁**/
synchronized (mSurfaceHolder) {
&&&&/**拿到当前画布 然后锁定**/
&&&&mCanvas =mSurfaceHolder.lockCanvas();
&&&&Draw();
&&&&/**绘制结束后解锁显示在屏幕上**/
&&&&mSurfaceHolder.unlockCanvasAndPost(mCanvas);
/**取得更新游戏结束的时间**/
long endTime = System.currentTimeMillis();&
/**计算出游戏一次更新的毫秒数**/
int diffTime&&= (int)(endTime - startTime);&
/**确保每次更新时间为30帧**/
while(diffTime &=TIME_IN_FRAME) {
&&&&diffTime = (int)(System.currentTimeMillis() - startTime);
&&&&/**线程等待**/
&&&&Thread.yield();
}& &&&&} }
最后由于代码较多我就不贴在博客中了 , 下面给出Demo源码的下载地址欢迎大家下载阅读互相学习,互相研究,互相讨论 雨松MOMO希望可以和大家一起进步。
下载地址:
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!

我要回帖

 

随机推荐