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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章