SurfaceView实现双缓冲避免游戏闪屏

发布时间:2017-1-20 9:34:12 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"SurfaceView实现双缓冲避免游戏闪屏",主要涉及到SurfaceView实现双缓冲避免游戏闪屏方面的内容,对于SurfaceView实现双缓冲避免游戏闪屏感兴趣的同学可以参考一下。

双缓冲技术是游戏开发中的一个重要的技术,主要原理是:当一个动画争先显示时,程序又在改变它,前面还没有显示完,程序又请求重新绘制,这样屏幕就会不停地闪烁。而双驵冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上 双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。  本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图: 对比一下,右边动画的帧速明显比左边的快,左右两者都没使用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 }

上一篇:设计模式(22)——解释器模式
下一篇:C++中的const

相关文章

相关评论