Android圖形系統之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之間的聯繫 && camera的takePicture實例

(1)Surface       


簡單翻譯:Surface是原始圖像緩衝區(raw buffer)的一個句柄,而原始圖像緩衝區是由屏幕圖像合成器(screen compositor)管理的。

        就如在C語言編程一樣,通過一個文件的句柄,就可以操作文件。 同樣的,通過Surface就可以獲取raw buffer其中的內容。當得到一個Surface對象時,同時會得到一個Canvas(畫布)對象。這一點可以通過查看\frameworks\base\core\java\android\view\Surface.java文件可知道Surface類定義了一個Canvas成員變量
(2)Canvas

         理解Canvas對象,可以把它當做畫布,Canvas的方法大多數是設置畫布的大小、形狀、畫布背景顏色等等,要想在畫布上面畫畫,一般要與Paint對象結合使用,顧名思義,Paint就是畫筆的風格,顏料的色彩之類的。如下:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. // 創建畫筆       
  2. Paint paint = new Paint();      
  3. paint.setColor(Color.RED);// 設置紅色       
  4. canvas.drawCircle(602010, paint);// 畫一個圓      
       Surface本身的作用類似一個句柄,得到了這個句柄就可以得到其中的Canvas、原生緩衝器以及其它方面的內容。Surface實現了Parcelable接口,(implements Parcelable),也就是說Surface對象可以把顯示內容的數據寫入到 Parcel 中,並且能夠從Parcel讀回數據。

(3)SurfaceView

          你可以通過SurfaceHolder這個接口去訪問Surface,而執行getHolder()方法可以得到SurfaceHolder接口。當SurfaceView的窗口可見時,Surface就會被創建,當SurfaceView窗口隱藏時,Surface就會被銷燬。當然了,你也可以通過複寫surfaceCreated(SurfaceHolder) 和 surfaceDestroyed(SurfaceHolder)  這兩個方法來驗證一下Surface何時被創建與何時被銷燬。

           SurfaceView與Surface的聯繫:簡單來說,Surface是管理顯示內容的數據(implementsParcelable),包括存儲數據的交換。而SurfaceView就是把這些數據顯示出來到屏幕上面。

(4)SurfaceHolder


          SurfaceHolder是一個接口,其作用就像一個關於Surface的監聽器,SurfaceHolder控制surface的流程所使用的幾個方法:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. abstract void     addCallback(SurfaceHolder.Callback callback)      //Add a Callback interface for this holder  
  2. abstract Canvas   lockCanvas()      //Start editing the pixels in the surface   
  3. abstract Canvas   lockCanvas(Rect dirty)        //Just like lockCanvas() but allows specification of a dirty rectangle  
  4. abstract void     removeCallback(SurfaceHolder.Callback callback)   //Removes a previously added Callback interface from this holder  
  5. abstract void     unlockCanvasAndPost(Canvas canvas)        //Finish editing pixels in the surface  

在SurfaceView中有一個方法getHolder,可以很方便地獲得SurfaceView所對應的Surface所對應的SurfaceHolder。

(5)SurfaceHolder.Callback

          Class Overview:A client may implement this interface to receive information about changes to the surface. When used with aSurfaceView, the Surface being held is only available between calls tosurfaceCreated(SurfaceHolder) andsurfaceDestroyed(SurfaceHolder). The Callback is set with SurfaceHolder.addCallback method.

主要方法:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height)        //invoked when surface changes  
  2. public abstract void surfaceCreated(SurfaceHolder holder)       //The SurfaceHolder whose surface is being created  
  3. public abstract void surfaceDestroyed(SurfaceHolder holder) //The SurfaceHolder whose surface is being destroyed.  
(6)附上上述所說幾種的聯繫
SurfaceHolder = SurfaceView.getHolder();   
Surface = SurfaceHolder.getSurface();  
Canvas =SurfaceHolder.LockCanvas(Rect dirty)  
Canvas   =Surface.lockCanvas(Rect dirty)  
         從設計模式的高度來看,Surface、SurfaceView和SurfaceHolder實質上就是廣爲人知的MVC,即Model-View-Controller。Model就是模型的意思,或者更簡單地說就是數據,也就是這裏的Surface;View即視圖,代表用戶交互界面,也就是這裏的SurfaceView;SurfaceHolder很明顯可以理解爲MVC中的Controller(控制器)。這樣看起來三者之間的關係就清楚了很多。

 ========================================================================================================

         給大家來一個使用camera.takePicture拍照的案例,這個是使用android.hardware.Camera硬件方式的,使用的都是camera.class標準接口。代碼如下:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.example.cameraandroid;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5.   
  6. import java.io.File;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9.   
  10. import android.content.Context;  
  11. import android.content.Intent;  
  12. import android.graphics.PixelFormat;  
  13. import android.hardware.Camera;  
  14. import android.hardware.Camera.Parameters;  
  15. import android.hardware.Camera.PictureCallback;   //拍照的回調接口  
  16. import android.hardware.Camera.ShutterCallback;   //快門的回調接口  
  17. import android.media.AudioManager;  
  18. import android.media.ToneGenerator;  
  19. import android.net.Uri;  
  20. import android.os.Environment;  
  21. import android.os.StatFs;  
  22. import android.util.Log;  
  23. import android.view.Menu;  
  24. import android.view.MenuItem;      //MENU鍵功能項  
  25. import android.view.SurfaceHolder;  
  26. import android.view.SurfaceView;  
  27.   
  28.   
  29. public class CameraAndroid extends Activity {  
  30.     private static final String TAG = "zhangcheng";  
  31.     private CameraPreview preview;  
  32.          private Camera camera;  
  33.          private ToneGenerator tone;  
  34.          private static final int OPTION_SNAPSHOT = 0;   //MENU項的值  
  35.   
  36.   
  37.     @Override  
  38.     protected void onCreate(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.         //setContentView(R.layout.activity_camera_android);  
  41.         preview = new CameraPreview(this);       //自定義的view  
  42.                   setContentView(preview);  
  43.     }  
  44.   
  45.     public boolean onOptionsItemSelected(MenuItem item) {   //activity的選項選擇函數  
  46.         Log.i(TAG,"onOptionsItemSelected");  
  47.                   int itemId = item.getItemId();               //獲得自定義ID  
  48.                   switch(itemId){  
  49.                        case OPTION_SNAPSHOT:  
  50.                 //拍攝照片  
  51.                            camera.takePicture(shutterCallback, null, jpegCallback);   //拍照動作  
  52.                         break;  
  53.                    }  
  54.                    return true;  
  55.     }  
  56.       
  57.     private PictureCallback jpegCallback = new PictureCallback(){  
  58.         @Override  
  59.         public void onPictureTaken(byte[] data, Camera camera) {  
  60.             Log.i(TAG,"jpegCallback");  
  61.             // TODO Auto-generated method stub  
  62.             Parameters ps = camera.getParameters();  
  63.                            if(ps.getPictureFormat() == PixelFormat.JPEG){  
  64.                                //存儲拍照獲得的圖片  
  65.                                     String path = save(data);  
  66.                                //將圖片交給Image程序處理  
  67.                                     Uri uri = Uri.fromFile(new File(path));  
  68.                                Intent intent = new Intent();  
  69.                                intent.setAction("android.intent.action.VIEW");  
  70.                                intent.setDataAndType(uri, "image/jpeg");  
  71.                                startActivity(intent);     //顯示剛纔拍的照片  
  72.             }        
  73.         }         
  74.     };  
  75.       
  76.     private ShutterCallback shutterCallback = new ShutterCallback(){  
  77.   
  78.         @Override  
  79.         public void onShutter() {  
  80.             Log.i(TAG,"shutterCallback");  
  81.             // TODO Auto-generated method stub  
  82.             if(tone == null)  
  83.                 //發出提示用戶的聲音  
  84.                                       tone = new ToneGenerator(AudioManager.STREAM_MUSIC,ToneGenerator.MAX_VOLUME);  
  85.             tone.startTone(ToneGenerator.TONE_PROP_BEEP2);  
  86.         }  
  87.     };  
  88.   
  89.     private String save(byte[] data){               //保存jpg到SD卡中  
  90.         String path = "/sdcard/"+System.currentTimeMillis()+".jpg";  
  91.         try{  
  92.             if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  
  93.                 //判斷SD卡上是否有足夠的空間  
  94.                                         String storage = Environment.getExternalStorageDirectory().toString();  
  95.                                   StatFs fs = new StatFs(storage);  
  96.                                   long available = fs.getAvailableBlocks()*fs.getBlockSize();  
  97.                                   if(available<data.length){  
  98.                                       //空間不足直接返回空  
  99.                                              return null;  
  100.                                    }  
  101.                                    File file = new File(path);  
  102.                                    if(!file.exists())  
  103.                                      //創建文件  
  104.                                               file.createNewFile();  
  105.                                    FileOutputStream fos = new FileOutputStream(file);  
  106.                                    fos.write(data);  
  107.                                    fos.close();  
  108.             }  
  109.         }catch(Exception e){  
  110.             e.printStackTrace();  
  111.             return null;  
  112.         }  
  113.         return path;  
  114.     }  
  115.       
  116.     class CameraPreview extends SurfaceView implements SurfaceHolder.Callback{  //完成自定義的CameraPreview  
  117.         SurfaceHolder mHolder;  
  118.         public CameraPreview(Context context) {   //view必有帶Context的構造函數  
  119.             super(context);  
  120.             // TODO Auto-generated constructor stub  
  121.             mHolder = getHolder();  
  122.                            mHolder.addCallback(this);  
  123.                            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  124.         }  
  125.   
  126.         @Override  
  127.         public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {  
  128.             Log.i(TAG,"surfaceChanged");  
  129.             // TODO Auto-generated method stub  
  130.             //已經獲得Surface的width和height,設置Camera的參數  
  131.                                 Camera.Parameters parameters = camera.getParameters();  
  132.                             parameters.setPreviewSize(width,height);  
  133.                             camera.setParameters(parameters);     //設置完效果後必須有這個  
  134.                             //開始預覽  
  135.                                  camera.startPreview();  
  136.         }  
  137.   
  138.         @Override  
  139.         public void surfaceCreated(SurfaceHolder holder) {  
  140.             Log.i(TAG,"surfaceCreated");  
  141.             // TODO Auto-generated method stub  
  142.             camera = Camera.open();  
  143.                            try {  
  144.                             //設置顯示  
  145.                                       camera.setPreviewDisplay(holder);//使預覽在surfaceview上顯示出來  
  146.                            } catch (IOException exception) {  
  147.                                  camera.release();  
  148.                                  camera = null;  
  149.                            }  
  150.         }  
  151.   
  152.         @Override  
  153.         public void surfaceDestroyed(SurfaceHolder holder) {  
  154.             Log.i(TAG,"surfaceDestroyed");  
  155.             // TODO Auto-generated method stub  
  156.             camera.stopPreview();  
  157.                             //釋放Camera  
  158.                             camera.release();  
  159.                             camera = null;  
  160.         }         
  161.     }  
  162.       
  163.     @Override  
  164.     public boolean onCreateOptionsMenu(Menu menu) {  
  165.         // Inflate the menu; this adds items to the action bar if it is present.  
  166.         //getMenuInflater().inflate(R.menu.camera_android, menu);  
  167.         menu.add(0, OPTION_SNAPSHOT, 0, R.string.snapshot);    //添加自定義meunitme項目  
  168.         return  super.onCreateOptionsMenu(menu);      
  169.     }  
  170. }  

      注意在androidmanifest.XML中加上硬件操作權限申明,如下:

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <uses-permission android:name="android.permission.CAMERA" />  
  2. <uses-feature android:name="android.hardware.camera" />  
  3. <uses-feature android:name="android.hardware.camera.autofocus" />  

      程序的運行結果就是:全屏預覽了一個攝像頭取景,如果按menu鍵,會激活“snapshot” 項,單擊它就可以拍照並預覽相片。


        以上是採用camera.java的API實現的camera相機方式,其實camera應用相機方式還有另外一種:就是直接調用系統相機,本質就是採用intent直接跳轉到系統相機。關鍵代碼如下:intent.setAction("android.media.action.STILL_IMAGE_CAMERA");   //此action是mediastore類裏面的定義


原文地址:http://blog.chinaunix.net/u/23353/showart_1898839.html

參考原文:http://www.cmd100.com/bbs/forum.php?mod=viewthread&tid=148031

參考原文:http://www.cnblogs.com/hnrainll/archive/2012/06/04/2534935.html

參考原文:http://www.cnblogs.com/xuling/archive/2011/06/06/android.html

參考原文:http://www.linuxidc.com/Linux/2012-08/67619p3.htm

參考原文:http://blog.csdn.net/pathuang68/article/details/7351317

發佈了7 篇原創文章 · 獲贊 5 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章