歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android教程-使用SurfaceView多線程繪制動畫

Android教程-使用SurfaceView多線程繪制動畫

日期:2017/3/1 10:19:54   编辑:Linux編程

Android教程之使用SurfaceView中的Surface對象進行繪圖,其本質就是利用SurfaceHolder的lockCanvas獲取到Canvas對象進行繪制的,對於繪制動畫來說,必須使用雙緩沖,或者采用雙線程,一個線程負責專門的預處理,比如圖片數據讀取,另外一個線程負責進行專繪制圖形。因為SurfaceView每次繪圖都會鎖定Canvas,也就是說同一片區域這次沒畫完下次就不能畫,因此要提高動畫播放的效率,就得開一條線程專門畫圖,開另外一條線程做預處理的工作。

下在給出一個例子,講解一下如何利用雙線程提高繪圖速度:

以下可以看到的動畫是一張解碼後的圖片從最屏幕最左邊快速移到右邊,重新開始則清屏進行顯示

  1. package com.test.surfaceview;
  2. import java.lang.reflect.Field;
  3. import java.util.ArrayList;
  4. import android.app.Activity;
  5. import android.content.Context;
  6. import android.graphics.Bitmap;
  7. import android.graphics.BitmapFactory;
  8. import android.graphics.Canvas;
  9. import android.graphics.Color;
  10. import android.graphics.Paint;
  11. import android.graphics.Rect;
  12. import android.os.Bundle;
  13. import android.util.Log;
  14. import android.view.SurfaceHolder;
  15. import android.view.SurfaceView;
  16. public class TestsurfaceviewActivity extends Activity {
  17. private final static String TAG = "TestsurfaceviewActivity";
  18. /** Called when the activity is first created. */
  19. @Override
  20. public void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.main);
  23. // setContentView(new MySurfaceView(this)); // 這裡以MySurfaceView作為顯示View
  24. onTestInit();
  25. }
  26. private SurfaceView drawSV = null;
  27. private SurfaceHolder drawSH = null;
  28. ArrayList<Integer> imgList = new ArrayList<Integer>();
  29. private int mWidth= 0, mHeight = 0;
  30. private Bitmap bitmap = null;
  31. private LoadImage loadImg = new LoadImage();
  32. private DrawImage drawImg = null;
  33. private void onTestInit() {
  34. drawSV = (SurfaceView) this.findViewById(R.id.SurfaceDrawView);
  35. drawSH = drawSV.getHolder();
  36. drawSH.addCallback(new MySVCallback());
  37. }
  38. private int onTestStart(){
  39. if(loadImg != null){
  40. loadImg.start();
  41. }
  42. drawImg = new DrawImage(0,mHeight);
  43. drawImg.start();
  44. return 0;
  45. }
  46. private void onTestStop(){
  47. if(loadImg != null){
  48. loadImg.stop();
  49. }
  50. if(drawImg != null){
  51. drawImg.stop();
  52. }
  53. }
  54. private class MySVCallback implements SurfaceHolder.Callback {
  55. @Override
  56. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  57. int height) {
  58. // TODO Auto-generated method stub
  59. Log.i(TAG, "surfaceChanged is called");
  60. }
  61. @Override
  62. public void surfaceCreated(SurfaceHolder holder) {
  63. // TODO Auto-generated method stub
  64. Log.i(TAG, "surfaceCreated is called");
  65. // 用反射機制來獲取資源中的圖片ID和尺寸
  66. Field[] fields = R.drawable.class.getDeclaredFields();
  67. for (Field field : fields) {
  68. // 除了icon及launcher之外的圖片
  69. if (!"icon".equals(field.getName())
  70. && !"ic_launcher".equals(field.getName())) {
  71. int index = 0;
  72. try {
  73. index = field.getInt(R.drawable.class);
  74. } catch (IllegalArgumentException e) {
  75. // TODO Auto-generated catch block
  76. e.printStackTrace();
  77. } catch (IllegalAccessException e) {
  78. // TODO Auto-generated catch block
  79. e.printStackTrace();
  80. }
  81. // 保存圖片ID
  82. imgList.add(index);
  83. }
  84. }
  85. Log.i(TAG,"imglist size = "+imgList.size());
  86. // 取得圖像大小
  87. Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
  88. imgList.get(0));
  89. mWidth = bmImg.getWidth();
  90. mHeight = bmImg.getHeight();
  91. onTestStart();
  92. }
  93. @Override
  94. public void surfaceDestroyed(SurfaceHolder holder) {
  95. // TODO Auto-generated method stub
  96. Log.i(TAG, "surfaceDestroyed is called");
  97. }
  98. }
  99. private class LoadImage extends Thread {
  100. private int imgIndex = 0;
  101. public void run() {
  102. while (true) {
  103. bitmap = BitmapFactory.decodeResource(getResources(),
  104. imgList.get(imgIndex));
  105. ++imgIndex;
  106. if (imgIndex == imgList.size()) { // 循環取圖片數據
  107. imgIndex = 0;
  108. }
  109. }
  110. }
  111. }
  112. private class DrawImage extends Thread{
  113. private int x,y;
  114. public DrawImage(int x,int y){
  115. this.x = x;
  116. this.y = y;
  117. }
  118. private void ClearScreen(){
  119. Canvas canvas = drawSH.lockCanvas(null);
  120. canvas.drawColor(Color.BLACK);// 清除畫布
  121. drawSH.unlockCanvasAndPost(canvas);
  122. }
  123. public void run() {
  124. while (true) {
  125. if (bitmap != null) {
  126. /**
  127. * 以下兩個有明顯的效率差異,lockCanvas()指定Rect內減少循環畫線的次數,
  128. * 可以提高繪圖效率,全屏刷新時會很閃爍
  129. */
  130. Canvas c = drawSH.lockCanvas(new Rect(this.x, this.y,
  131. this.x + mWidth, this.y + mHeight));
  132. // Canvas c = drawSH.lockCanvas();
  133. c.drawBitmap(bitmap, this.x, this.y, new Paint());
  134. drawSH.unlockCanvasAndPost(c);// 將顯示內容上屏
  135. this.x += 10;
  136. //如果到了終點,則清屏重來
  137. if(this.x > 1280 - mWidth){
  138. this.x = 0;
  139. ClearScreen();
  140. }
  141. }
  142. }
  143. }
  144. }
  145. }
Copyright © Linux教程網 All Rights Reserved