SurfaceView 双缓冲应用

双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。 

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

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

代码片段(3)[全屏查看所有代码]

1. [图片] 程序运行截图    

2. [代码]main.xml     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/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     跳至 [2] [3] [全屏预览]

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package com.testSurfaceView;
 
import java.lang.reflect.Field;
import java.util.ArrayList;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
 
public class TestSurfaceView extends Activity {
     /** Called when the activity is first created. */
     Button btnSingleThread, btnDoubleThread;
     SurfaceView sfv;
     SurfaceHolder sfh;
     ArrayList<Integer> imgList = new ArrayList<Integer>();
     int imgWidth, imgHeight;
     Bitmap bitmap; //独立线程读取,独立线程绘图
 
     @Override
     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 {
 
         @Override
         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 {
 
         @Override
         public void surfaceChanged(SurfaceHolder holder, int format, int width,
                 int height) {
             Log.i( "Surface:" , "Change" );
 
         }
 
         @Override
         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 ;
                     try {
                         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();
         }
 
         @Override
         public void surfaceDestroyed(SurfaceHolder holder) {
             Log.i( "Surface:" , "Destroy" );
 
         }
 
     }
 
     /**
      * 读取并显示图片的线程
      */
     class Load_DrawImage extends Thread {
         int x, y;
         int imgIndex = 0 ;
 
         public Load_DrawImage( int x, int y) {
             this .x = x;
             this .y = 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 {
         int x, y;
 
         public DrawImage( int x, int y) {
             this .x = x;
             this .y = 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 ;
             }
         }
     };
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值