Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android提高第三篇之SurfaceView(下)

Android提高第三篇之SurfaceView(下)

編輯:Android開發實例

        上一篇簡單介紹了SurfaceView的使用,這次就介紹SurfaceView的雙緩沖使用。雙緩沖是為了防止動畫閃爍而實現的一種多線程應用,基於SurfaceView的雙緩沖實現很簡單,開一條線程並在其中繪圖即可。本文介紹基於SurfaceView的雙緩沖實現,以及介紹類似的更高效的實現方法。

        本文程序運行截圖如下,左邊是開單個線程讀取並繪圖,右邊是開兩個線程,一個專門讀取圖片,一個專門繪圖:

對比一下,右邊動畫的幀速明顯比左邊的快,左右兩者都沒使用Thread.sleep()。為什麼要開兩個線程一個讀一個畫,而不去開兩個線程像左邊那樣都“邊讀邊畫”呢?因為SurfaceView每次繪圖都會鎖定Canvas,也就是說同一片區域這次沒畫完下次就不能畫,因此要提高雙緩沖的效率,就得開一條線程專門畫圖,開另外一條線程做預處理的工作。

main.xml的源碼:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="fill_parent" android:layout_height="fill_parent" 
  4.     android:orientation="vertical"> 
  5.  
  6.     <LinearLayout android:id="@+id/LinearLayout01" 
  7.         android:layout_width="wrap_content" android:layout_height="wrap_content"> 
  8.         <Button android:id="@+id/Button01" android:layout_width="wrap_content" 
  9.             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> 

 

 

本文程序的源碼:

 

  1. package com.testSurfaceView;     
  2.     
  3. import java.lang.reflect.Field;     
  4. import java.util.ArrayList;     
  5. import android.app.Activity;     
  6. import android.graphics.Bitmap;     
  7. import android.graphics.BitmapFactory;     
  8. import android.graphics.Canvas;     
  9. import android.graphics.Paint;     
  10. import android.graphics.Rect;     
  11. import android.os.Bundle;     
  12. import android.util.Log;     
  13. import android.view.SurfaceHolder;     
  14. import android.view.SurfaceView;     
  15. import android.view.View;     
  16. import android.widget.Button;     
  17.     
  18. public class testSurfaceView extends Activity {     
  19.     /** Called when the activity is first created. */    
  20.     Button btnSingleThread, btnDoubleThread;     
  21.     SurfaceView sfv;     
  22.     SurfaceHolder sfh;     
  23.     ArrayList<Integer> imgList = new ArrayList<Integer>();     
  24.     int imgWidth, imgHeight;     
  25.     Bitmap bitmap;//獨立線程讀取,獨立線程繪圖     
  26.     
  27.     @Override    
  28.     public void onCreate(Bundle savedInstanceState) {     
  29.         super.onCreate(savedInstanceState);     
  30.         setContentView(R.layout.main);     
  31.     
  32.         btnSingleThread = (Button) this.findViewById(R.id.Button01);     
  33.         btnDoubleThread = (Button) this.findViewById(R.id.Button02);     
  34.         btnSingleThread.setOnClickListener(new ClickEvent());     
  35.         btnDoubleThread.setOnClickListener(new ClickEvent());     
  36.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);     
  37.         sfh = sfv.getHolder();     
  38.         sfh.addCallback(new MyCallBack());// 自動運行surfaceCreated以及surfaceChanged     
  39.     }     
  40.     
  41.     class ClickEvent implements View.OnClickListener {     
  42.     
  43.         @Override    
  44.         public void onClick(View v) {     
  45.     
  46.             if (v == btnSingleThread) {     
  47.                 new Load_DrawImage(0, 0).start();//開一條線程讀取並繪圖     
  48.             } else if (v == btnDoubleThread) {     
  49.                 new LoadImage().start();//開一條線程讀取     
  50.                 new DrawImage(imgWidth + 10, 0).start();//開一條線程繪圖     
  51.             }     
  52.     
  53.         }     
  54.     
  55.     }     
  56.     
  57.     class MyCallBack implements SurfaceHolder.Callback {     
  58.     
  59.         @Override    
  60.         public void surfaceChanged(SurfaceHolder holder, int format, int width,     
  61.                 int height) {     
  62.             Log.i("Surface:", "Change");     
  63.     
  64.         }     
  65.     
  66.         @Override    
  67.         public void surfaceCreated(SurfaceHolder holder) {     
  68.             Log.i("Surface:", "Create");     
  69.     
  70.             // 用反射機制來獲取資源中的圖片ID和尺寸     
  71.             Field[] fields = R.drawable.class.getDeclaredFields();     
  72.             for (Field field : fields) {     
  73.                 if (!"icon".equals(field.getName()))// 除了icon之外的圖片     
  74.                 {     
  75.                     int index = 0;     
  76.                     try {     
  77.                         index = field.getInt(R.drawable.class);     
  78.                     } catch (IllegalArgumentException e) {     
  79.                         // TODO Auto-generated catch block     
  80.                         e.printStackTrace();     
  81.                     } catch (IllegalAccessException e) {     
  82.                         // TODO Auto-generated catch block     
  83.                         e.printStackTrace();     
  84.                     }     
  85.                     // 保存圖片ID     
  86.                     imgList.add(index);     
  87.                 }     
  88.             }     
  89.             // 取得圖像大小     
  90.             Bitmap bmImg = BitmapFactory.decodeResource(getResources(),     
  91.                     imgList.get(0));     
  92.             imgWidth = bmImg.getWidth();     
  93.             imgHeight = bmImg.getHeight();     
  94.         }     
  95.     
  96.         @Override    
  97.         public void surfaceDestroyed(SurfaceHolder holder) {     
  98.             Log.i("Surface:", "Destroy");     
  99.     
  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. }   

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved