当前位置: 代码迷 >> Android >> Android 的 SurfaceView 双缓冲运用
  详细解决方案

Android 的 SurfaceView 双缓冲运用

热度:130   发布时间:2016-05-01 16:59:35.0
Android 的 SurfaceView 双缓冲应用
双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。

本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。



main.xml
view sourceprint?
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>
[代码] TestSurfaceView.java
view sourceprint?
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 }
  相关解决方案