`

Android提高第三篇之SurfaceView(下)

 
阅读更多

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

上一篇简单介绍了SurfaceView的使用,这次就介绍SurfaceView的双缓冲使用。双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于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. }

分享到:
评论

相关推荐

    Android提高第三篇之SurfaceView与多线程的混搭.docx

    在本篇文章中,我们将深入探讨如何将SurfaceView与多线程相结合,以避免动画闪烁并提升性能。 首先,了解Android中多线程的基本概念。Android应用的主线程负责处理UI更新和用户交互,为了不阻塞主线程,复杂的计算...

    Android提高第二篇之SurfaceView(上).doc

    SurfaceView 是 Android 中一种特殊的视图,它允许开发者在后台线程中进行高效、低延迟的图形绘制,特别适用于需要实时更新画面的应用场景,如游戏、视频播放等。在本文中,我们将深入探讨 SurfaceView 的基本用法和...

    Android中SurfaceView截屏

    在Android开发中,`SurfaceView`是一个非常重要的视图组件,尤其在处理视频播放、游戏渲染等高性能图形操作时,它的优势在于拥有独立于主线程的渲染机制,能避免阻塞UI更新。然而,由于其特殊的性质,直接通过常规...

    android SurfaceView做二维码扫描源码

    总的来说,实现"android SurfaceView做二维码扫描源码"涉及到Android的SurfaceView使用、摄像头控制、图像处理以及第三方库的集成等多个技术点。理解并掌握这些知识点,才能开发出高效稳定的二维码扫描应用。

    Android SurfaceView 实现实时显示摄像头视频

    本篇文章将深入探讨如何利用`SurfaceView`实现实时显示摄像头视频。 首先,我们需要了解`SurfaceView`的基本原理。`SurfaceView`包含一个独立的渲染表面,它位于窗口管理器的单独层上,与应用程序的其他UI组件分离...

    android surfaceview自定义拍照 绘制头像轮廓

    在Android开发中,`SurfaceView`是一个非常重要的组件,它提供了与硬件图形渲染直接交互的能力。...通过理解并实践这个项目,开发者可以深入学习Android的底层图形处理以及如何利用第三方库增强应用程序的功能。

    Android SurfaceView实现人物动画

    在Android开发中,SurfaceView是一种特殊的视图,它允许开发者在应用程序中创建高性能的...实践中,可以结合其他的动画库,如Android的Property Animation API,或者第三方库如NineOldAndroids,来进一步丰富动画效果。

    Android进阶篇之引导页系列之强大的SurfaceView实现动画引导页(2)

    在这个"Android进阶篇之引导页系列之强大的SurfaceView实现动画引导页(2)"中,我们将深入探讨如何利用SurfaceView来创建动态且引人入胜的引导页动画。 SurfaceView是Android系统提供的一种特殊视图,它允许开发者...

    Android SurfaceView实现加载GIF动画

    Android原生并不支持GIF格式,所以通常我们会选择第三方库,如 Glide、Picasso 或者 Android-Universal-Image-Loader 等,这些库都提供了加载和播放GIF的功能。在这里,我们将以一个常用的库,如 Glide 为例。 1. *...

    android surfaceview 播放视频

    SurfaceView创建了一个独立的显示表面,这个表面位于应用窗口之上,与应用程序主线程分离,从而可以在后台线程中进行渲染,提高性能。这对于处理视频流非常有利,因为视频解码和渲染可以在这个独立的线程中进行,...

    android上下滑动引导页 上下切换页面 手势判断 SurfaceView实现

    在不使用任何第三方库的情况下,我们可以自定义一个布局管理器来处理页面的滑动和切换逻辑。 1. **布局设计**: - 可以使用`ViewPager`作为基础框架,`ViewPager`支持左右滑动切换页面,但不直接支持上下滑动。...

    android 摇摇棒 之surfaceView vs. View--第二届 Google 暑期大学生博客分享大赛 - 2011 Android 成长篇

    本篇文章主要探讨了在Android中使用SurfaceView和View两种不同的方法来处理摇摇棒事件,这是在2011年第二届Google暑期大学生博客分享大赛中的一个Android成长篇主题。我们将深入分析这两个组件在处理传感器数据和...

    Android开发提高

    #### Android提高第二、三篇之SurfaceView SurfaceView是Android中用于实时渲染图形的组件,特别适用于处理视频或游戏等动态视觉内容。在提高篇中,SurfaceView被细分为上下两部分进行深入讲解,这反映了其复杂性和...

    surfaceview实现抽奖转盘

    SurfaceView在Android开发中是一种特殊的View,主要用于处理高性能、低延迟的图形绘制,例如游戏、视频播放或像抽奖转盘这样的复杂动画。SurfaceView通过创建一个独立的Surface,并将其渲染到窗口上,允许UI更新与...

    android 使用SurfaceView实现小球高处落下并弹起的效果

    总结来说,利用Android的SurfaceView,结合基本的物理原理,我们可以创建出一个逼真的小球落下并弹起的动画。这是一个很好的起点,对于想要深入Android游戏开发的人来说,可以进一步扩展到更复杂的游戏机制,如多...

    双SurfaceView的使用

    3. **叠加SurfaceView**:为了让顶层的SurfaceView(绘制图形的)覆盖底层的SurfaceView(摄像头预览),你可以使用`RelativeLayout`或`FrameLayout`作为父布局,并设置合适的层级关系。例如,通过设置`android:...

    surfaceview网络视频播放

    在实际项目中,可能会涉及到更复杂的场景,比如使用自定义的MediaExtractor或MediaCodec来处理解码,或者使用ijkplayer、ExoPlayer等第三方库来增强播放功能和兼容性。`tzt_mediavideo`这个文件可能包含了一些示例...

Global site tag (gtag.js) - Google Analytics