Android提高第三篇之SurfaceView(下)

本文来自http://blog.csdn.net/hellogv/,引用必须注明出处!

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

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

Android提高第三篇之SurfaceView(下)

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

main.xml的源码:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"android:layout_height="fill_parent"
  4. android:orientation="vertical">
  5. <LinearLayoutandroid:id="@+id/LinearLayout01"
  6. android:layout_width="wrap_content"android:layout_height="wrap_content">
  7. <Buttonandroid:id="@+id/Button01"android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"android:text="单个独立线程"></Button>
  9. <Buttonandroid:id="@+id/Button02"android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"android:text="两个独立线程"></Button>
  11. </LinearLayout>
  12. <SurfaceViewandroid:id="@+id/SurfaceView01"
  13. android:layout_width="fill_parent"android:layout_height="fill_parent"></SurfaceView>
  14. </LinearLayout>

本文程序的源码:

  1. packagecom.testSurfaceView;
  2. importjava.lang.reflect.Field;
  3. importjava.util.ArrayList;
  4. importandroid.app.Activity;
  5. importandroid.graphics.Bitmap;
  6. importandroid.graphics.BitmapFactory;
  7. importandroid.graphics.Canvas;
  8. importandroid.graphics.Paint;
  9. importandroid.graphics.Rect;
  10. importandroid.os.Bundle;
  11. importandroid.util.Log;
  12. importandroid.view.SurfaceHolder;
  13. importandroid.view.SurfaceView;
  14. importandroid.view.View;
  15. importandroid.widget.Button;
  16. publicclasstestSurfaceViewextendsActivity{
  17. /**Calledwhentheactivityisfirstcreated.*/
  18. ButtonbtnSingleThread,btnDoubleThread;
  19. SurfaceViewsfv;
  20. SurfaceHoldersfh;
  21. ArrayList<Integer>imgList=newArrayList<Integer>();
  22. intimgWidth,imgHeight;
  23. Bitmapbitmap;//独立线程读取,独立线程绘图
  24. @Override
  25. publicvoidonCreate(BundlesavedInstanceState){
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.main);
  28. btnSingleThread=(Button)this.findViewById(R.id.Button01);
  29. btnDoubleThread=(Button)this.findViewById(R.id.Button02);
  30. btnSingleThread.setOnClickListener(newClickEvent());
  31. btnDoubleThread.setOnClickListener(newClickEvent());
  32. sfv=(SurfaceView)this.findViewById(R.id.SurfaceView01);
  33. sfh=sfv.getHolder();
  34. sfh.addCallback(newMyCallBack());//自动运行surfaceCreated以及surfaceChanged
  35. }
  36. classClickEventimplementsView.OnClickListener{
  37. @Override
  38. publicvoidonClick(Viewv){
  39. if(v==btnSingleThread){
  40. newLoad_DrawImage(0,0).start();//开一条线程读取并绘图
  41. }elseif(v==btnDoubleThread){
  42. newLoadImage().start();//开一条线程读取
  43. newDrawImage(imgWidth+10,0).start();//开一条线程绘图
  44. }
  45. }
  46. }
  47. classMyCallBackimplementsSurfaceHolder.Callback{
  48. @Override
  49. publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,
  50. intheight){
  51. Log.i("Surface:","Change");
  52. }
  53. @Override
  54. publicvoidsurfaceCreated(SurfaceHolderholder){
  55. Log.i("Surface:","Create");
  56. //用反射机制来获取资源中的图片ID和尺寸
  57. Field[]fields=R.drawable.class.getDeclaredFields();
  58. for(Fieldfield:fields){
  59. if(!"icon".equals(field.getName()))//除了icon之外的图片
  60. {
  61. intindex=0;
  62. try{
  63. index=field.getInt(R.drawable.class);
  64. }catch(IllegalArgumentExceptione){
  65. //TODOAuto-generatedcatchblock
  66. e.printStackTrace();
  67. }catch(IllegalAccessExceptione){
  68. //TODOAuto-generatedcatchblock
  69. e.printStackTrace();
  70. }
  71. //保存图片ID
  72. imgList.add(index);
  73. }
  74. }
  75. //取得图像大小
  76. BitmapbmImg=BitmapFactory.decodeResource(getResources(),
  77. imgList.get(0));
  78. imgWidth=bmImg.getWidth();
  79. imgHeight=bmImg.getHeight();
  80. }
  81. @Override
  82. publicvoidsurfaceDestroyed(SurfaceHolderholder){
  83. Log.i("Surface:","Destroy");
  84. }
  85. }
  86. /*
  87. *读取并显示图片的线程
  88. */
  89. classLoad_DrawImageextendsThread{
  90. intx,y;
  91. intimgIndex=0;
  92. publicLoad_DrawImage(intx,inty){
  93. this.x=x;
  94. this.y=y;
  95. }
  96. publicvoidrun(){
  97. while(true){
  98. Canvasc=sfh.lockCanvas(newRect(this.x,this.y,this.x
  99. +imgWidth,this.y+imgHeight));
  100. BitmapbmImg=BitmapFactory.decodeResource(getResources(),
  101. imgList.get(imgIndex));
  102. c.drawBitmap(bmImg,this.x,this.y,newPaint());
  103. imgIndex++;
  104. if(imgIndex==imgList.size())
  105. imgIndex=0;
  106. sfh.unlockCanvasAndPost(c);//更新屏幕显示内容
  107. }
  108. }
  109. };
  110. /*
  111. *只负责绘图的线程
  112. */
  113. classDrawImageextendsThread{
  114. intx,y;
  115. publicDrawImage(intx,inty){
  116. this.x=x;
  117. this.y=y;
  118. }
  119. publicvoidrun(){
  120. while(true){
  121. if(bitmap!=null){//如果图像有效
  122. Canvasc=sfh.lockCanvas(newRect(this.x,this.y,this.x
  123. +imgWidth,this.y+imgHeight));
  124. c.drawBitmap(bitmap,this.x,this.y,newPaint());
  125. sfh.unlockCanvasAndPost(c);//更新屏幕显示内容
  126. }
  127. }
  128. }
  129. };
  130. /*
  131. *只负责读取图片的线程
  132. */
  133. classLoadImageextendsThread{
  134. intimgIndex=0;
  135. publicvoidrun(){
  136. while(true){
  137. bitmap=BitmapFactory.decodeResource(getResources(),
  138. imgList.get(imgIndex));
  139. imgIndex++;
  140. if(imgIndex==imgList.size())//如果到尽头则重新读取
  141. imgIndex=0;
  142. }
  143. }
  144. };
  145. }

你可能感兴趣的:(SurfaceView)