android 自定义相机

简介: <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; line-height:35px"> <span style="font-size:14px">老规矩,先上一下项目地址:

老规矩,先上一下项目地址:GitHub:https://github.com/xiangzhihong/CameraDemo

方式:

  • 调用Camera API 自定义相机
  • 调用系统相机

由于需求不同,所以选择的方案固然也不同,至于第二种调用系统相机,这里就不过多讲解了,使用Intent对象设置一个Action动作即可,跳转时使用startActivityForResult,然后在onActivityResult处理相关数据便可,关键代码:

[java]  view plain  copy
 print ?
  1. intent.setAction("android.media.action.STILL_IMAGE_CAMERA");  

至于使用,较常见的一般是应用中用户上传头像的时候调用,然后返回处理图像数据。


而第一种自定义相机的方式使用也十分普遍,但是要做好这个模块,相对来说还是有一定难度的,之前分享过一个Github上的开源相机的项目,项目由美国的一个团队开发,集 拍照、摄影、各种特效动画 等功能与一身,本人之前研究了下,发现功能比较全面也很强大,抠出来单独拍照那一个模块,我滴妈呀,真TM费劲!相机不管是预览还是拍摄图像都还是很清晰的,自己当时也写了一个,比较操蛋,只能怪自己对这一块的优化了解浅显吧!特别是预览的时候,聚焦完成后,焦点周边会出现很多白色的噪点,密密麻麻,特别严重,头疼的很。不过也总算解决了,灰常感谢USA的那个什么什么团队的开源相机程序。经过自己改造后的预览效果图:




下面看下这个项目的效果图,我也把地址甩底,大伙感兴趣的自行Clone研究(或者闲的蛋疼也可以抽时间剥离开每一个模块学习,作为日后的知识储备),里面也用到了这个Android中读取图片EXIF元数据之metadata-extractor的使用





相机开发简介

下面说说在Android中调用Camera来定义相机的最基本步骤:

  1. 打开相机 —— 调用Camera的open()方法。
  2. 获取拍照参数 —— 调用Camera的getParameters()方法,返回Camera.Parameters对象。
  3. 拍照参数设置 —— 调用Camera.Parameters对象。
  4. 拍照参数控制 —— 调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入。注:Android2.3.3之后不用设置。
  5. 预览取景 —— 调用Camera的startPreview()方法,在之前注意调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。
  6. 拍照 —— 调用Camera的takePicture()
  7. 停止预览 —— 调用Camera的stopPreview()方法
  8. 资源释放 —— Camera.release()

开启和关闭预览的联系如下:Camera ---- SurfaceHolder ------ SurfaceView

关于SurfaceHolder.Callback必须实现的3个方法:

surfaceCreated() 该方法在surfaceView被Create时调用
surfaceChanged() 该方法是当surfaceView发生改变后调用
surfaceDestroyed() 这个不用说了,销毁时调用

surfaceHolder通过addCallBack()方法将响应的接口绑定


注:必要Camera权限,例如:

[html]  view plain  copy
 print ?
  1. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
  2.   
  3. <uses-permission android:name="android.permission.CAMERA"/>  
  4.   
  5. <uses-feature android:name="android.hardware.camera" />  
  6.   
  7. <uses-permission android:name="android.hardware.camera.autofocus" />  
  8.   
  9. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  


关于Camera下的Parameters类,其中封装了我们需要的大部分功能,下面做个简单介绍:

  1. setPictureFormat() 方法用于设置相机照片的格式,其参数是一个字符型参数,位于PixelFormat类中,如:PixelFormat.JPEG。
  2. setSceneMode() 方法用于设置相机场景类型,其参是是一个字符型参数,位于Parameters类中,以SCENE_MODE_开头。
  3. setZoom() 方法用于设置相机焦距,其参数是一个整型的参数,该参数的范围是0到Camera.getParameters().getMaxZoom()。
  4. setPictureSize() 方法用于设置相机照片的大小,参数为整型。
  5. setWhiteBalance() 方法用于设置相机照片白平衡,其参数是一个字符型,位于Parameters类中,以WHITE_BALANCE开头。
  6. setJpegQuality() 方法用于设置相机照片的质量,其参数是一个整型参数,取值范围为1到100。
  7. setFlashMode() 方法用于设置闪光灯的类型,其参数是一个字符型参数,位于Parameters类中,以FLASH_MODE_开头。
  8. setColorEffect() 方法用于设置照片颜色特效的类型,其参数是一个字符型参数,位于Parameters类中,以EFFECT_开头。


本程序模块效果图及示例


下面分享本篇Blog的示例相机模块,此功能模块并非上面开源项目中的剥离出来的,看下效果图咯:

         


         



效果看着还可以吧(不点赞也太不给面子了吧  - . - ),下面个出主界面的布局代码:

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/layout"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent" >  
  6.   
  7.     <!-- 预览画布 -->  
  8.     <SurfaceView  
  9.         android:id="@+id/surfaceView"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="match_parent" />  
  12.   
  13.     <!-- 闪光灯、前置摄像头、后置摄像头、聚焦 -->  
  14.   
  15.     <RelativeLayout  
  16.         android:layout_width="match_parent"  
  17.         android:layout_height="match_parent" >  
  18.   
  19.         <org.gaochun.camera.CameraGrid  
  20.             android:id="@+id/camera_grid"  
  21.             android:layout_width="match_parent"  
  22.             android:layout_height="match_parent"  
  23.             android:layout_alignParentTop="true" />  
  24.   
  25.         <View  
  26.             android:id="@+id/focus_index"  
  27.             android:layout_width="40dp"  
  28.             android:layout_height="40dp"  
  29.             android:background="@drawable/camera_focus"  
  30.             android:visibility="invisible" />  
  31.   
  32.         <ImageView  
  33.             android:id="@+id/flash_view"  
  34.             android:layout_width="wrap_content"  
  35.             android:layout_height="wrap_content"  
  36.             android:layout_alignParentLeft="true"  
  37.             android:onClick="onClick"  
  38.             android:padding="15dp"  
  39.             android:scaleType="centerCrop"  
  40.             android:src="@drawable/camera_flash_off" />  
  41.   
  42.         <ImageView  
  43.             android:id="@+id/camera_flip_view"  
  44.             android:layout_width="wrap_content"  
  45.             android:layout_height="wrap_content"  
  46.             android:layout_alignParentRight="true"  
  47.             android:onClick="onClick"  
  48.             android:padding="15dp"  
  49.             android:scaleType="centerCrop"  
  50.             android:src="@drawable/camera_flip" />  
  51.   
  52.         <!-- 底部按钮 -->  
  53.   
  54.         <RelativeLayout  
  55.             android:layout_width="fill_parent"  
  56.             android:layout_height="70dp"  
  57.             android:layout_alignParentBottom="true"  
  58.             android:background="#a0000000"  
  59.             android:padding="5dp" >  
  60.   
  61.             <Button  
  62.                 android:id="@+id/search"  
  63.                 android:layout_width="wrap_content"  
  64.                 android:layout_height="wrap_content"  
  65.                 android:layout_marginLeft="30dp"  
  66.                 android:background="@null"  
  67.                 android:drawablePadding="3dp"  
  68.                 android:drawableTop="@drawable/ic_search_selector"  
  69.                 android:onClick="onClick"  
  70.                 android:text="搜图"  
  71.                 android:textColor="@drawable/row_selector_text" />  
  72.   
  73.             <ImageView  
  74.                 android:id="@+id/action_button"  
  75.                 android:layout_width="wrap_content"  
  76.                 android:layout_height="wrap_content"  
  77.                 android:layout_centerInParent="true"  
  78.                 android:clickable="true"  
  79.                 android:onClick="onClick"  
  80.                 android:src="@drawable/btn_shutter_photo" />  
  81.   
  82.             <Button  
  83.                 android:id="@+id/takephoto"  
  84.                 android:layout_width="wrap_content"  
  85.                 android:layout_height="wrap_content"  
  86.                 android:layout_alignParentRight="true"  
  87.                 android:layout_marginRight="30dp"  
  88.                 android:background="@null"  
  89.                 android:drawablePadding="3dp"  
  90.                 android:drawableTop="@drawable/ic_takephoto_selector"  
  91.                 android:onClick="onClick"  
  92.                 android:text="拍照"  
  93.                 android:textColor="@drawable/row_selector_text" />  
  94.         </RelativeLayout>  
  95.     </RelativeLayout>  
  96.   
  97. </FrameLayout>  


下面是核心模块 CameraPreview 类:

[java]  view plain  copy
 print ?
  1. public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback, Camera.AutoFocusCallback {  
  2.   
  3.     private SurfaceView mSurfaceView;  
  4.     private SurfaceHolder mHolder;  
  5.     private Size mPreviewSize;  
  6.     private Size adapterSize;  
  7.     //private List<Size> mSupportedPreviewSizes;  
  8.     private Camera mCamera;  
  9.     private boolean isSupportAutoFocus = false;  
  10.     private Camera.Parameters parameters = null;  
  11.     private Context mContext;  
  12.     //private int mCurrentCameraId = 0;  
  13.     private int screenWidth;  
  14.     private int screenHeight;  
  15.   
  16.     CameraPreview(Context context, SurfaceView sv) {  
  17.         super(context);  
  18.         mContext = context;  
  19.         mSurfaceView = sv;  
  20.         mHolder = mSurfaceView.getHolder();  
  21.         mHolder.addCallback(this);  
  22.         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  23.         mHolder.setKeepScreenOn(true);  
  24.         isSupportAutoFocus = context.getPackageManager().hasSystemFeature(  
  25.                 PackageManager.FEATURE_CAMERA_AUTOFOCUS);  
  26.         DisplayMetrics dm = new DisplayMetrics();  
  27.         ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);  
  28.         screenWidth = dm.widthPixels;  
  29.         screenHeight = dm.heightPixels;  
  30.     }  
  31.   
  32.     public void setCamera(Camera camera) {  
  33.         mCamera = camera;  
  34.         initCamera();  
  35.     }  
  36.   
  37.     public void initCamera() {  
  38.         if (mCamera != null) {  
  39.             Camera.Parameters params = mCamera.getParameters();  
  40.             //mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();  
  41.             requestLayout();  
  42.             if (mPreviewSize == null) {  
  43.                 mPreviewSize = findBestPreviewResolution();  
  44.             }  
  45.             if (adapterSize == null) {  
  46.                 adapterSize = findBestPictureResolution();  
  47.             }  
  48.             if (adapterSize != null) {  
  49.                 params.setPictureSize(adapterSize.width, adapterSize.height);  
  50.             }  
  51.             if (mPreviewSize != null) {  
  52.                 params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);  
  53.             }  
  54.             params.setPictureFormat(PixelFormat.JPEG);  
  55.             List<String> focusModes = params.getSupportedFocusModes();  
  56.             if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {  
  57.                 // set the focus mode  
  58.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  59.                 // set Camera parameters  
  60.                 mCamera.setParameters(params);  
  61.             }  
  62.             setDispaly(params, mCamera);  
  63.             //setCameraDisplayOrientation((Activity) mContext, mCurrentCameraId, mCamera);  
  64.             mCamera.setParameters(params);  
  65.         }  
  66.     }  
  67.   
  68.     //控制图像的正确显示方向  
  69.     private void setDispaly(Camera.Parameters parameters, Camera camera) {  
  70.         if (Build.VERSION.SDK_INT >= 8) {  
  71.             setDisplayOrientation(camera, 90);  
  72.         } else {  
  73.             parameters.setRotation(90);  
  74.         }  
  75.     }  
  76.   
  77.     //实现的图像的正确显示  
  78.     private void setDisplayOrientation(Camera camera, int i) {  
  79.         Method downPolymorphic;  
  80.         try {  
  81.             downPolymorphic = camera.getClass().getMethod("setDisplayOrientation",  
  82.                     new Class[]{int.class});  
  83.             if (downPolymorphic != null) {  
  84.                 downPolymorphic.invoke(camera, new Object[]{i});  
  85.             }  
  86.         } catch (Exception e) {  
  87.             e.printStackTrace();  
  88.         }  
  89.     }  
  90.   
  91.     public static void setCameraDisplayOrientation(Activity activity,  
  92.             int cameraId, android.hardware.Camera camera) {  
  93.         android.hardware.Camera.CameraInfo info =  
  94.                 new android.hardware.Camera.CameraInfo();  
  95.         android.hardware.Camera.getCameraInfo(cameraId, info);  
  96.         int rotation = activity.getWindowManager().getDefaultDisplay()  
  97.                 .getRotation();  
  98.         int degrees = 0;  
  99.         switch (rotation) {  
  100.         case Surface.ROTATION_0:  
  101.             degrees = 0;  
  102.             break;  
  103.         case Surface.ROTATION_90:  
  104.             degrees = 90;  
  105.             break;  
  106.         case Surface.ROTATION_180:  
  107.             degrees = 180;  
  108.             break;  
  109.         case Surface.ROTATION_270:  
  110.             degrees = 270;  
  111.             break;  
  112.         }  
  113.   
  114.         int result;  
  115.         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {  
  116.             result = (info.orientation + degrees) % 360;  
  117.             result = (360 - result) % 360;  // compensate the mirror  
  118.         } else {  // back-facing  
  119.             result = (info.orientation - degrees + 360) % 360;  
  120.         }  
  121.         camera.setDisplayOrientation(result);  
  122.     }  
  123.   
  124.     @Override  
  125.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  126.         final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);  
  127.         final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);  
  128.         setMeasuredDimension(width, height);  
  129.         //        if (mSupportedPreviewSizes != null) {  
  130.         //             mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);  
  131.         //        }  
  132.     }  
  133.   
  134.     @Override  
  135.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  136.         if (changed && getChildCount() > 0) {  
  137.             final View child = getChildAt(0);  
  138.   
  139.             final int width = r - l;  
  140.             final int height = b - t;  
  141.   
  142.             int previewWidth = width;  
  143.             int previewHeight = height;  
  144.             if (mPreviewSize != null) {  
  145.                 previewWidth = mPreviewSize.width;  
  146.                 previewHeight = mPreviewSize.height;  
  147.             }  
  148.   
  149.             // Center the child SurfaceView within the parent.  
  150.             if (width * previewHeight > height * previewWidth) {  
  151.                 final int scaledChildWidth = previewWidth * height / previewHeight;  
  152.                 child.layout((width - scaledChildWidth) / 20,  
  153.                         (width + scaledChildWidth) / 2, height);  
  154.             } else {  
  155.                 final int scaledChildHeight = previewHeight * width / previewWidth;  
  156.                 child.layout(0, (height - scaledChildHeight) / 2,  
  157.                         width, (height + scaledChildHeight) / 2);  
  158.             }  
  159.         }  
  160.     }  
  161.   
  162.     public void surfaceCreated(SurfaceHolder holder) {  
  163.         // The Surface has been created, acquire the camera and tell it where  
  164.         // to draw.  
  165.         try {  
  166.             if (mCamera != null) {  
  167.                 mCamera.setPreviewDisplay(holder);  
  168.             }  
  169.         } catch (IOException e) {  
  170.             if (null != mCamera) {  
  171.                 mCamera.release();  
  172.                 mCamera = null;  
  173.   
  174.             }  
  175.             e.printStackTrace();  
  176.         }  
  177.     }  
  178.   
  179.     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {  
  180.         if (holder.getSurface() == null) {  
  181.             return;  
  182.         }  
  183.         if (mCamera != null) {  
  184.             Camera.Parameters parameters = mCamera.getParameters();  
  185.             parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);  
  186.             mCamera.setParameters(parameters);  
  187.             try {  
  188.                 mCamera.setPreviewDisplay(holder);  
  189.             } catch (IOException e) {  
  190.                 e.printStackTrace();  
  191.             }  
  192.             mCamera.startPreview();  
  193.             reAutoFocus();  
  194.         }  
  195.     }  
  196.   
  197.     public void surfaceDestroyed(SurfaceHolder holder) {  
  198.         // Surface will be destroyed when we return, so stop the preview.  
  199.         if (mCamera != null) {  
  200.             mCamera.stopPreview();  
  201.         }  
  202.     }  
  203.   
  204.     /** 
  205.      * 最小预览界面的分辨率 
  206.      */  
  207.     private static final int MIN_PREVIEW_PIXELS = 480 * 320;  
  208.     /** 
  209.      * 最大宽高比差 
  210.      */  
  211.     private static final double MAX_ASPECT_DISTORTION = 0.15;  
  212.   
  213.     /** 
  214.      * 找出最适合的预览界面分辨率 
  215.      * 
  216.      * @return 
  217.      */  
  218.     private Camera.Size findBestPreviewResolution() {  
  219.         Camera.Parameters cameraParameters = mCamera.getParameters();  
  220.         Camera.Size defaultPreviewResolution = cameraParameters.getPreviewSize();  
  221.   
  222.         List<Camera.Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();  
  223.         if (rawSupportedSizes == null) {  
  224.             return defaultPreviewResolution;  
  225.         }  
  226.   
  227.         // 按照分辨率从大到小排序  
  228.         List<Camera.Size> supportedPreviewResolutions = new ArrayList<Camera.Size>(rawSupportedSizes);  
  229.         Collections.sort(supportedPreviewResolutions, new Comparator<Size>() {  
  230.             @Override  
  231.             public int compare(Camera.Size a, Camera.Size b) {  
  232.                 int aPixels = a.height * a.width;  
  233.                 int bPixels = b.height * b.width;  
  234.                 if (bPixels < aPixels) {  
  235.                     return -1;  
  236.                 }  
  237.                 if (bPixels > aPixels) {  
  238.                     return 1;  
  239.                 }  
  240.                 return 0;  
  241.             }  
  242.         });  
  243.   
  244.         StringBuilder previewResolutionSb = new StringBuilder();  
  245.         for (Camera.Size supportedPreviewResolution : supportedPreviewResolutions) {  
  246.             previewResolutionSb.append(supportedPreviewResolution.width).append('x').append(supportedPreviewResolution.height)  
  247.             .append(' ');  
  248.         }  
  249.   
  250.   
  251.         // 移除不符合条件的分辨率  
  252.         double screenAspectRatio = (double) screenWidth  
  253.         / screenHeight;  
  254.         Iterator<Size> it = supportedPreviewResolutions.iterator();  
  255.         while (it.hasNext()) {  
  256.             Camera.Size supportedPreviewResolution = it.next();  
  257.             int width = supportedPreviewResolution.width;  
  258.             int height = supportedPreviewResolution.height;  
  259.   
  260.             // 移除低于下限的分辨率,尽可能取高分辨率  
  261.             if (width * height < MIN_PREVIEW_PIXELS) {  
  262.                 it.remove();  
  263.                 continue;  
  264.             }  
  265.   
  266.             // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率  
  267.             // 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height  
  268.             // 因此这里要先交换然preview宽高比后在比较  
  269.             boolean isCandidatePortrait = width > height;  
  270.             int maybeFlippedWidth = isCandidatePortrait ? height : width;  
  271.             int maybeFlippedHeight = isCandidatePortrait ? width : height;  
  272.             double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;  
  273.             double distortion = Math.abs(aspectRatio - screenAspectRatio);  
  274.             if (distortion > MAX_ASPECT_DISTORTION) {  
  275.                 it.remove();  
  276.                 continue;  
  277.             }  
  278.   
  279.             // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回  
  280.             if (maybeFlippedWidth == screenWidth  
  281.                     && maybeFlippedHeight == screenHeight) {  
  282.                 return supportedPreviewResolution;  
  283.             }  
  284.         }  
  285.   
  286.   
  287.         // 如果没有找到合适的,并且还有候选的像素,则设置其中最大比例的,对于配置比较低的机器不太合适  
  288.         if (!supportedPreviewResolutions.isEmpty()) {  
  289.             Camera.Size largestPreview = supportedPreviewResolutions.get(0);  
  290.             return largestPreview;  
  291.         }  
  292.   
  293.   
  294.         // 没有找到合适的,就返回默认的  
  295.   
  296.         return defaultPreviewResolution;  
  297.     }  
  298.   
  299.   
  300.     private Camera.Size findBestPictureResolution() {  
  301.         Camera.Parameters cameraParameters = mCamera.getParameters();  
  302.         List<Camera.Size> supportedPicResolutions = cameraParameters.getSupportedPictureSizes(); // 至少会返回一个值  
  303.   
  304.         StringBuilder picResolutionSb = new StringBuilder();  
  305.         for (Camera.Size supportedPicResolution : supportedPicResolutions) {  
  306.             picResolutionSb.append(supportedPicResolution.width).append('x')  
  307.             .append(supportedPicResolution.height).append(" ");  
  308.         }  
  309.   
  310.         Camera.Size defaultPictureResolution = cameraParameters.getPictureSize();  
  311.   
  312.         // 排序  
  313.         List<Camera.Size> sortedSupportedPicResolutions = new ArrayList<Camera.Size>(  
  314.                 supportedPicResolutions);  
  315.         Collections.sort(sortedSupportedPicResolutions, new Comparator<Camera.Size>() {  
  316.             @Override  
  317.             public int compare(Camera.Size a, Camera.Size b) {  
  318.                 int aPixels = a.height * a.width;  
  319.                 int bPixels = b.height * b.width;  
  320.                 if (bPixels < aPixels) {  
  321.                     return -1;  
  322.                 }  
  323.                 if (bPixels > aPixels) {  
  324.                     return 1;  
  325.                 }  
  326.                 return 0;  
  327.             }  
  328.         });  
  329.   
  330.   
  331.         // 移除不符合条件的分辨率  
  332.         double screenAspectRatio = screenWidth  
  333.         / (double) screenHeight;  
  334.         Iterator<Camera.Size> it = sortedSupportedPicResolutions.iterator();  
  335.         while (it.hasNext()) {  
  336.             Camera.Size supportedPreviewResolution = it.next();  
  337.             int width = supportedPreviewResolution.width;  
  338.             int height = supportedPreviewResolution.height;  
  339.   
  340.             // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率  
  341.             // 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height  
  342.             // 因此这里要先交换然后在比较宽高比  
  343.             boolean isCandidatePortrait = width > height;  
  344.             int maybeFlippedWidth = isCandidatePortrait ? height : width;  
  345.             int maybeFlippedHeight = isCandidatePortrait ? width : height;  
  346.             double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;  
  347.             double distortion = Math.abs(aspectRatio - screenAspectRatio);  
  348.             if (distortion > MAX_ASPECT_DISTORTION) {  
  349.                 it.remove();  
  350.                 continue;  
  351.             }  
  352.         }  
  353.   
  354.         // 如果没有找到合适的,并且还有候选的像素,对于照片,则取其中最大比例的,而不是选择与屏幕分辨率相同的  
  355.         if (!sortedSupportedPicResolutions.isEmpty()) {  
  356.             return sortedSupportedPicResolutions.get(0);  
  357.         }  
  358.   
  359.         // 没有找到合适的,就返回默认的  
  360.         return defaultPictureResolution;  
  361.     }  
  362.   
  363.     private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {  
  364.         final double ASPECT_TOLERANCE = 0.1;  
  365.         double targetRatio = (double) w / h;  
  366.         if (sizes == null)  
  367.             return null;  
  368.   
  369.         Size optimalSize = null;  
  370.         double minDiff = Double.MAX_VALUE;  
  371.   
  372.         int targetHeight = h;  
  373.   
  374.         // Try to find an size match aspect ratio and size  
  375.         for (Size size : sizes) {  
  376.             double ratio = (double) size.width / size.height;  
  377.             if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)  
  378.                 continue;  
  379.             if (Math.abs(size.height - targetHeight) < minDiff) {  
  380.                 optimalSize = size;  
  381.                 minDiff = Math.abs(size.height - targetHeight);  
  382.             }  
  383.         }  
  384.   
  385.         // Cannot find the one match the aspect ratio, ignore the requirement  
  386.         if (optimalSize == null) {  
  387.             minDiff = Double.MAX_VALUE;  
  388.             for (Size size : sizes) {  
  389.                 if (Math.abs(size.height - targetHeight) < minDiff) {  
  390.                     optimalSize = size;  
  391.                     minDiff = Math.abs(size.height - targetHeight);  
  392.                 }  
  393.             }  
  394.         }  
  395.         return optimalSize;  
  396.     }  
  397.   
  398.   
  399.     public void reAutoFocus() {  
  400.         if (isSupportAutoFocus) {  
  401.             mCamera.autoFocus(new Camera.AutoFocusCallback() {  
  402.                 @Override  
  403.                 public void onAutoFocus(boolean success, Camera camera) {  
  404.                 }  
  405.             });  
  406.         }  
  407.     }  
  408.   
  409.     public List<Size> getResolutionList() {  
  410.         return mCamera.getParameters().getSupportedPreviewSizes();  
  411.     }  
  412.   
  413.     public Camera.Size getResolution() {  
  414.         Camera.Parameters params = mCamera.getParameters();  
  415.         Camera.Size s = params.getPreviewSize();  
  416.         return s;  
  417.     }  
  418.   
  419.     /*public void setCurrentCameraId(int current) { 
  420.         mCurrentCameraId = current; 
  421.     }*/  
  422.   
  423.     //定点对焦的代码  
  424.     public void pointFocus(MotionEvent event) {  
  425.         mCamera.cancelAutoFocus();  
  426.         parameters = mCamera.getParameters();  
  427.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  428.             //showPoint(x, y);  
  429.             focusOnTouch(event);  
  430.         }  
  431.         mCamera.setParameters(parameters);  
  432.         autoFocus();  
  433.     }  
  434.   
  435.     //实现自动对焦  
  436.     public void autoFocus() {  
  437.         new Thread() {  
  438.             @Override  
  439.             public void run() {  
  440.                 try {  
  441.                     sleep(100);  
  442.                 } catch (InterruptedException e) {  
  443.                     e.printStackTrace();  
  444.                 }  
  445.                 if (mCamera == null) {  
  446.                     return;  
  447.                 }  
  448.                 mCamera.autoFocus(new Camera.AutoFocusCallback() {  
  449.                     @Override  
  450.                     public void onAutoFocus(boolean success, Camera camera) {  
  451.                         if (success) {  
  452.                             initCamera();//实现相机的参数初始化  
  453.                         }  
  454.                     }  
  455.                 });  
  456.             }  
  457.         };  
  458.     }  
  459.   
  460.     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)  
  461.     private void showPoint(int x, int y) {  
  462.         if (parameters.getMaxNumMeteringAreas() > 0) {  
  463.             List<Camera.Area> areas = new ArrayList<Camera.Area>();  
  464.             WindowManager wm = (WindowManager) getContext()  
  465.                     .getSystemService(Context.WINDOW_SERVICE);  
  466.             //xy变换了  
  467.             int rectY = -x * 2000 / wm.getDefaultDisplay().getWidth() + 1000;  
  468.             int rectX = y * 2000 / wm.getDefaultDisplay().getHeight() - 1000;  
  469.             int left = rectX < -900 ? -1000 : rectX - 100;  
  470.             int top = rectY < -900 ? -1000 : rectY - 100;  
  471.             int right = rectX > 900 ? 1000 : rectX + 100;  
  472.             int bottom = rectY > 900 ? 1000 : rectY + 100;  
  473.             Rect area1 = new Rect(left, top, right, bottom);  
  474.             areas.add(new Camera.Area(area1, 800));  
  475.             parameters.setMeteringAreas(areas);  
  476.         }  
  477.   
  478.         parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);  
  479.     }  
  480.   
  481.     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)  
  482.     public void focusOnTouch(MotionEvent event) {  
  483.         Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);  
  484.         Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f);  
  485.   
  486.         Camera.Parameters parameters = mCamera.getParameters();  
  487.         parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  488.   
  489.         if (parameters.getMaxNumFocusAreas() > 0) {  
  490.             List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();  
  491.             focusAreas.add(new Camera.Area(focusRect, 1000));  
  492.   
  493.             parameters.setFocusAreas(focusAreas);  
  494.         }  
  495.   
  496.         if (parameters.getMaxNumMeteringAreas() > 0) {  
  497.             List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();  
  498.             meteringAreas.add(new Camera.Area(meteringRect, 1000));  
  499.   
  500.             parameters.setMeteringAreas(meteringAreas);  
  501.         }  
  502.         mCamera.setParameters(parameters);  
  503.         mCamera.autoFocus(this);  
  504.     }  
  505.   
  506.     /** 
  507.      * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000. 
  508.      */  
  509.     private Rect calculateTapArea(float x, float y, float coefficient) {  
  510.         float focusAreaSize = 300;  
  511.         int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();  
  512.   
  513.         int centerX = (int) (x / getResolution().width * 2000 - 1000);  
  514.         int centerY = (int) (y / getResolution().height * 2000 - 1000);  
  515.   
  516.         int left = clamp(centerX - areaSize / 2, -10001000);  
  517.         int right = clamp(left + areaSize, -10001000);  
  518.         int top = clamp(centerY - areaSize / 2, -10001000);  
  519.         int bottom = clamp(top + areaSize, -10001000);  
  520.   
  521.         return new Rect(left, top, right, bottom);  
  522.     }  
  523.   
  524.     private int clamp(int x, int min, int max) {  
  525.         if (x > max) {  
  526.             return max;  
  527.         }  
  528.         if (x < min) {  
  529.             return min;  
  530.         }  
  531.         return x;  
  532.     }  
  533.   
  534.     @Override  
  535.     public void onAutoFocus(boolean success, Camera camera) {  
  536.   
  537.     }  
  538.   
  539.     public void setNull() {  
  540.         adapterSize = null;  
  541.         mPreviewSize = null;  
  542.     }  
  543.   
  544. }  


以下是CameraActivity类:

[java]  view plain  copy
 print ?
  1. public class CameraActivity extends Activity implements View.OnTouchListener,OnClickListener {  
  2.   
  3.     public static final String CAMERA_PATH_VALUE1 = "PHOTO_PATH";  
  4.     public static final String CAMERA_PATH_VALUE2 = "PATH";  
  5.     public static final String CAMERA_TYPE = "CAMERA_TYPE";  
  6.     public static final String CAMERA_RETURN_PATH = "return_path";  
  7.   
  8.     private int PHOTO_SIZE_W = 2000;  
  9.     private int PHOTO_SIZE_H = 2000;  
  10.     public static final int CAMERA_TYPE_1 = 1;  
  11.     public static final int CAMERA_TYPE_2 = 2;  
  12.     private final int PROCESS = 1;  
  13.     private CameraPreview preview;  
  14.     private Camera camera;  
  15.     private Context mContext;  
  16.     private View focusIndex;  
  17.     private ImageView flashBtn;  
  18.     private int mCurrentCameraId = 0// 1是前置 0是后置  
  19.     private SurfaceView mSurfaceView;  
  20.     private CameraGrid mCameraGrid;  
  21.   
  22.     private int type = 1;   //引用的矩形框  
  23.   
  24.     private Button mBtnSearch;  
  25.     private Button mBtnTakePhoto;  
  26.   
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         mContext = this;  
  31.   
  32.         //requestWindowFeature(Window.FEATURE_NO_TITLE);  
  33.         //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏  
  34.         //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照过程屏幕一直处于高亮  
  35.         setContentView(R.layout.camera_home);  
  36.         type = getIntent().getIntExtra(CAMERA_TYPE, CAMERA_TYPE_2);  
  37.         initView();  
  38.         InitData();  
  39.   
  40.     }  
  41.   
  42.     private void initView() {  
  43.         focusIndex = (View) findViewById(R.id.focus_index);  
  44.         flashBtn = (ImageView) findViewById(R.id.flash_view);  
  45.         mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);  
  46.         mCameraGrid = (CameraGrid) findViewById(R.id.camera_grid);  
  47.         mBtnSearch = (Button) findViewById(R.id.search);  
  48.         mBtnTakePhoto = (Button) findViewById(R.id.takephoto);  
  49.     }  
  50.   
  51.   
  52.     private void InitData() {  
  53.         preview = new CameraPreview(this, mSurfaceView);  
  54.         preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,  
  55.                 LayoutParams.MATCH_PARENT));  
  56.         ((FrameLayout) findViewById(R.id.layout)).addView(preview);  
  57.         preview.setKeepScreenOn(true);  
  58.         mSurfaceView.setOnTouchListener(this);  
  59.         mCameraGrid.setType(type);  
  60.     }  
  61.   
  62.   
  63.   
  64.   
  65.     private Handler handler = new Handler();  
  66.   
  67.     private void takePhoto() {  
  68.         try {  
  69.   
  70.             camera.takePicture(shutterCallback, rawCallback, jpegCallback);  
  71.   
  72.         } catch (Throwable t) {  
  73.             t.printStackTrace();  
  74.             Toast.makeText(getApplication(), "拍照失败,请重试!", Toast.LENGTH_LONG)  
  75.             .show();  
  76.             try {  
  77.                 camera.startPreview();  
  78.             } catch (Throwable e) {  
  79.   
  80.             }  
  81.         }  
  82.     }  
  83.   
  84.   
  85.   
  86.     @Override  
  87.     protected void onResume() {  
  88.         super.onResume();  
  89.         int numCams = Camera.getNumberOfCameras();  
  90.         if (numCams > 0) {  
  91.             try {  
  92.                 mCurrentCameraId = 0;  
  93.                 camera = Camera.open(mCurrentCameraId);  
  94.                 camera.startPreview();  
  95.                 preview.setCamera(camera);  
  96.                 preview.reAutoFocus();  
  97.             } catch (RuntimeException ex) {  
  98.                 Toast.makeText(mContext, "未发现相机", Toast.LENGTH_LONG).show();  
  99.             }  
  100.         }  
  101.   
  102.     }  
  103.   
  104.   
  105.   
  106.     @Override  
  107.     protected void onPause() {  
  108.         if (camera != null) {  
  109.             camera.stopPreview();  
  110.             preview.setCamera(null);  
  111.             camera.release();  
  112.             camera = null;  
  113.             preview.setNull();  
  114.         }  
  115.         super.onPause();  
  116.   
  117.     }  
  118.   
  119.   
  120.     private void resetCam() {  
  121.         camera.startPreview();  
  122.         preview.setCamera(camera);  
  123.     }  
  124.   
  125.   
  126.     ShutterCallback shutterCallback = new ShutterCallback() {  
  127.         public void onShutter() {  
  128.         }  
  129.     };  
  130.   
  131.   
  132.     PictureCallback rawCallback = new PictureCallback() {  
  133.         public void onPictureTaken(byte[] data, Camera camera) {  
  134.         }  
  135.     };  
  136.   
  137.   
  138.     PictureCallback jpegCallback = new PictureCallback() {  
  139.         public void onPictureTaken(byte[] data, Camera camera) {  
  140.   
  141.             new SaveImageTask(data).execute();  
  142.             resetCam();  
  143.         }  
  144.     };  
  145.   
  146.   
  147.     @Override  
  148.     public boolean onTouch(View v, MotionEvent event) {  
  149.         try {  
  150.             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  151.                 preview.pointFocus(event);  
  152.             }  
  153.         } catch (Exception e) {  
  154.             e.printStackTrace();  
  155.         }  
  156.   
  157.         RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(  
  158.                 focusIndex.getLayoutParams());  
  159.         layout.setMargins((int) event.getX() - 60, (int) event.getY() - 600,0);  
  160.   
  161.         focusIndex.setLayoutParams(layout);  
  162.         focusIndex.setVisibility(View.VISIBLE);  
  163.   
  164.         ScaleAnimation sa = new ScaleAnimation(3f, 1f, 3f, 1f,  
  165.                 ScaleAnimation.RELATIVE_TO_SELF, 0.5f,  
  166.                 ScaleAnimation.RELATIVE_TO_SELF, 0.5f);  
  167.         sa.setDuration(800);  
  168.         focusIndex.startAnimation(sa);  
  169.         handler.postAtTime(new Runnable() {  
  170.             @Override  
  171.             public void run() {  
  172.                 focusIndex.setVisibility(View.INVISIBLE);  
  173.             }  
  174.         }, 800);  
  175.         return false;  
  176.     }  
  177.   
  178.   
  179.     @Override  
  180.     public void onClick(View v) {  
  181.         switch (v.getId()) {  
  182.   
  183.         /*case R.id.camera_back: 
  184.             setResult(0); 
  185.             finish(); 
  186.             break;*/  
  187.   
  188.         case R.id.camera_flip_view:  
  189.             switchCamera();  
  190.             break;  
  191.   
  192.         case R.id.flash_view:  
  193.             turnLight(camera);  
  194.             break;  
  195.   
  196.         case R.id.action_button:  
  197.             takePhoto();  
  198.             break;  
  199.   
  200.         case R.id.search:   //处理选中状态  
  201.             mBtnSearch.setSelected(true);  
  202.             mBtnTakePhoto.setSelected(false);  
  203.             break;  
  204.   
  205.         case R.id.takephoto:    //处理选中状态  
  206.             mBtnTakePhoto.setSelected(true);  
  207.             mBtnSearch.setSelected(false);  
  208.             break;  
  209.         }  
  210.     }  
  211.   
  212.     private static String getCameraPath() {  
  213.         Calendar calendar = Calendar.getInstance();  
  214.         StringBuilder sb = new StringBuilder();  
  215.         sb.append("IMG");  
  216.         sb.append(calendar.get(Calendar.YEAR));  
  217.         int month = calendar.get(Calendar.MONTH) + 1// 0~11  
  218.         sb.append(month < 10 ? "0" + month : month);  
  219.         int day = calendar.get(Calendar.DATE);  
  220.         sb.append(day < 10 ? "0" + day : day);  
  221.         int hour = calendar.get(Calendar.HOUR_OF_DAY);  
  222.         sb.append(hour < 10 ? "0" + hour : hour);  
  223.         int minute = calendar.get(Calendar.MINUTE);  
  224.         sb.append(minute < 10 ? "0" + minute : minute);  
  225.         int second = calendar.get(Calendar.SECOND);  
  226.         sb.append(second < 10 ? "0" + second : second);  
  227.         if (!new File(sb.toString() + ".jpg").exists()) {  
  228.             return sb.toString() + ".jpg";  
  229.         }  
  230.   
  231.         StringBuilder tmpSb = new StringBuilder(sb);  
  232.         int indexStart = sb.length();  
  233.         for (int i = 1; i < Integer.MAX_VALUE; i++) {  
  234.             tmpSb.append('(');  
  235.             tmpSb.append(i);  
  236.             tmpSb.append(')');  
  237.             tmpSb.append(".jpg");  
  238.             if (!new File(tmpSb.toString()).exists()) {  
  239.                 break;  
  240.             }  
  241.   
  242.             tmpSb.delete(indexStart, tmpSb.length());  
  243.         }  
  244.   
  245.         return tmpSb.toString();  
  246.     }  
  247.   
  248.   
  249.   
  250.     //处理拍摄的照片  
  251.     private class SaveImageTask extends AsyncTask<Void, Void, String> {  
  252.         private byte[] data;  
  253.   
  254.         SaveImageTask(byte[] data) {  
  255.             this.data = data;  
  256.         }  
  257.   
  258.         @Override  
  259.         protected String doInBackground(Void... params) {  
  260.             // Write to SD Card  
  261.             String path = "";  
  262.             try {  
  263.   
  264.                 showProgressDialog("处理中");  
  265.                 path = saveToSDCard(data);  
  266.   
  267.             } catch (FileNotFoundException e) {  
  268.                 e.printStackTrace();  
  269.             } catch (IOException e) {  
  270.                 e.printStackTrace();  
  271.             } finally {  
  272.             }  
  273.             return path;  
  274.         }  
  275.   
  276.   
  277.         @Override  
  278.         protected void onPostExecute(String path) {  
  279.             super.onPostExecute(path);  
  280.   
  281.             if (!TextUtils.isEmpty(path)) {  
  282.   
  283.                 Log.d("DemoLog""path=" + path);  
  284.   
  285.                 dismissProgressDialog();  
  286.                 Intent intent = new Intent();  
  287.                 intent.setClass(CameraActivity.this, PhotoProcessActivity.class);  
  288.                 intent.putExtra(CAMERA_PATH_VALUE1, path);  
  289.                 startActivityForResult(intent, PROCESS);  
  290.             } else {  
  291.                 Toast.makeText(getApplication(), "拍照失败,请稍后重试!",  
  292.                         Toast.LENGTH_LONG).show();  
  293.             }  
  294.         }  
  295.     }  
  296.   
  297.     private AlertDialog mAlertDialog;  
  298.   
  299.     private void dismissProgressDialog() {  
  300.         this.runOnUiThread(new Runnable() {  
  301.             @Override  
  302.             public void run() {  
  303.                 if (mAlertDialog != null && mAlertDialog.isShowing()  
  304.                         && !CameraActivity.this.isFinishing()) {  
  305.                     mAlertDialog.dismiss();  
  306.                     mAlertDialog = null;  
  307.                 }  
  308.             }  
  309.         });  
  310.     }  
  311.   
  312.     private void showProgressDialog(final String msg) {  
  313.         this.runOnUiThread(new Runnable() {  
  314.             @Override  
  315.             public void run() {  
  316.                 if (mAlertDialog == null) {  
  317.                     mAlertDialog = new GenericProgressDialog(  
  318.                             CameraActivity.this);  
  319.                 }  
  320.                 mAlertDialog.setMessage(msg);  
  321.                 ((GenericProgressDialog) mAlertDialog)  
  322.                 .setProgressVisiable(true);  
  323.                 mAlertDialog.setCancelable(false);  
  324.                 mAlertDialog.setOnCancelListener(null);  
  325.                 mAlertDialog.show();  
  326.                 mAlertDialog.setCanceledOnTouchOutside(false);  
  327.             }  
  328.         });  
  329.     }  
  330.   
  331.   
  332.     /** 
  333.      * 将拍下来的照片存放在SD卡中 
  334.      */  
  335.     public String saveToSDCard(byte[] data) throws IOException {  
  336.         Bitmap croppedImage;  
  337.         // 获得图片大小  
  338.         BitmapFactory.Options options = new BitmapFactory.Options();  
  339.         options.inJustDecodeBounds = true;  
  340.         BitmapFactory.decodeByteArray(data, 0, data.length, options);  
  341.         // PHOTO_SIZE = options.outHeight > options.outWidth ? options.outWidth  
  342.         // : options.outHeight;  
  343.         PHOTO_SIZE_W = options.outWidth;  
  344.         PHOTO_SIZE_H = options.outHeight;  
  345.         options.inJustDecodeBounds = false;  
  346.         Rect r = new Rect(00, PHOTO_SIZE_W, PHOTO_SIZE_H);  
  347.         try {  
  348.             croppedImage = decodeRegionCrop(data, r);  
  349.         } catch (Exception e) {  
  350.             return null;  
  351.         }  
  352.         String imagePath = "";  
  353.         try {  
  354.             imagePath = saveToFile(croppedImage);  
  355.         } catch (Exception e) {  
  356.   
  357.         }  
  358.         croppedImage.recycle();  
  359.         return imagePath;  
  360.     }  
  361.   
  362.   
  363.   
  364.     private Bitmap decodeRegionCrop(byte[] data, Rect rect) {  
  365.         InputStream is = null;  
  366.         System.gc();  
  367.         Bitmap croppedImage = null;  
  368.         try {  
  369.             is = new ByteArrayInputStream(data);  
  370.             BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is,false);  
  371.             try {  
  372.                 croppedImage = decoder.decodeRegion(rect,  
  373.                         new BitmapFactory.Options());  
  374.             } catch (IllegalArgumentException e) {  
  375.             }  
  376.         } catch (Throwable e) {  
  377.             e.printStackTrace();  
  378.         } finally {  
  379.   
  380.         }  
  381.         Matrix m = new Matrix();  
  382.         m.setRotate(90, PHOTO_SIZE_W / 2, PHOTO_SIZE_H / 2);  
  383.         if (mCurrentCameraId == 1) {  
  384.             m.postScale(1, -1);  
  385.         }  
  386.         Bitmap rotatedImage = Bitmap.createBitmap(croppedImage, 00,  
  387.                 PHOTO_SIZE_W, PHOTO_SIZE_H, m, true);  
  388.         if (rotatedImage != croppedImage)  
  389.             croppedImage.recycle();  
  390.         return rotatedImage;  
  391.     }  
  392.   
  393.   
  394.   
  395.     // 保存图片文件  
  396.     public static String saveToFile(Bitmap croppedImage)  
  397.             throws FileNotFoundException, IOException {  
  398.         File sdCard = Environment.getExternalStorageDirectory();  
  399.         File dir = new File(sdCard.getAbsolutePath() + "/DCIM/Camera/");  
  400.         if (!dir.exists()) {  
  401.             dir.mkdirs();  
  402.         }  
  403.         String fileName = getCameraPath();  
  404.         File outFile = new File(dir, fileName);  
  405.         FileOutputStream outputStream = new FileOutputStream(outFile); // 文件输出流  
  406.         croppedImage.compress(Bitmap.CompressFormat.JPEG, 70, outputStream);  
  407.         outputStream.flush();  
  408.         outputStream.close();  
  409.         return outFile.getAbsolutePath();  
  410.     }  
  411.   
  412.   
  413.     /** 
  414.      * 闪光灯开关 开->关->自动 
  415.      * 
  416.      * @param mCamera 
  417.      */  
  418.     private void turnLight(Camera mCamera) {  
  419.         if (mCamera == null || mCamera.getParameters() == null  
  420.                 || mCamera.getParameters().getSupportedFlashModes() == null) {  
  421.             return;  
  422.         }  
  423.         Camera.Parameters parameters = mCamera.getParameters();  
  424.         String flashMode = mCamera.getParameters().getFlashMode();  
  425.         List<String> supportedModes = mCamera.getParameters()  
  426.                 .getSupportedFlashModes();  
  427.         if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)  
  428.                 && supportedModes.contains(Camera.Parameters.FLASH_MODE_ON)) {// 关闭状态  
  429.             parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);  
  430.             mCamera.setParameters(parameters);  
  431.             flashBtn.setImageResource(R.drawable.camera_flash_on);  
  432.         } else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {// 开启状态  
  433.             if (supportedModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {  
  434.                 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);  
  435.                 flashBtn.setImageResource(R.drawable.camera_flash_auto);  
  436.                 mCamera.setParameters(parameters);  
  437.             } else if (supportedModes  
  438.                     .contains(Camera.Parameters.FLASH_MODE_OFF)) {  
  439.                 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);  
  440.                 flashBtn.setImageResource(R.drawable.camera_flash_off);  
  441.                 mCamera.setParameters(parameters);  
  442.             }  
  443.         } else if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)  
  444.                 && supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {  
  445.             parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);  
  446.             mCamera.setParameters(parameters);  
  447.             flashBtn.setImageResource(R.drawable.camera_flash_off);  
  448.         }  
  449.     }  
  450.   
  451.   
  452.     // 切换前后置摄像头  
  453.     private void switchCamera() {  
  454.         mCurrentCameraId = (mCurrentCameraId + 1) % Camera.getNumberOfCameras();  
  455.         if (camera != null) {  
  456.             camera.stopPreview();  
  457.             preview.setCamera(null);  
  458.             camera.setPreviewCallback(null);  
  459.             camera.release();  
  460.             camera = null;  
  461.         }  
  462.         try {  
  463.             camera = Camera.open(mCurrentCameraId);  
  464.             camera.setPreviewDisplay(mSurfaceView.getHolder());  
  465.             preview.setCamera(camera);  
  466.             camera.startPreview();  
  467.         } catch (Exception e) {  
  468.             Toast.makeText(mContext, "未发现相机", Toast.LENGTH_LONG).show();  
  469.         }  
  470.   
  471.     }  
  472.   
  473.     @Override  
  474.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  475.         if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {  
  476.             setResult(0);  
  477.             finish();  
  478.             return true;  
  479.         }  
  480.         return super.onKeyDown(keyCode, event);  
  481.     }  
  482.   
  483.   
  484.     @Override  
  485.     public void onActivityResult(int requestCode, int resultCode, Intent data) {  
  486.         if (requestCode == PROCESS) {  
  487.             if (resultCode == RESULT_OK) {  
  488.                 Intent intent = new Intent();  
  489.                 if (data != null) {  
  490.                     intent.putExtra(CAMERA_RETURN_PATH,  
  491.                             data.getStringExtra(CAMERA_PATH_VALUE2));  
  492.                 }  
  493.                 setResult(RESULT_OK, intent);  
  494.                 finish();  
  495.             } else {  
  496.                 if (data != null) {  
  497.                     File dir = new File(data.getStringExtra(CAMERA_PATH_VALUE2));  
  498.                     if (dir != null) {  
  499.                         dir.delete();  
  500.                     }  
  501.                 }  
  502.             }  
  503.         }  
  504.     }  
  505. }  


总结

1、网上有些示例代码,担心相机初始化及开启时间较长,将初始化及启动工作单独放在子线程中,偶尔出现黑屏的情况,但也不是经常出现。

导致原因:由于单独开辟了线程去初始化启动相机,导致相机的初始化和开启工作已完成,而找不到画布控件。若出现此情况,可调试或者将线程睡眠500毫秒。


2、按下home键后,再次进入时,为毛黑屏了,如何破?

导致原因:在onCreate中find了SurfaceView,按下Home后程序再次进入时,找不到预览的画布了,可将find的工作放入onResume中,再就是别忘了在onPause中做如下操作:

[java]  view plain  copy
 print ?
  1. @Override  
  2.     protected void onPause() {  
  3.         if (camera != null) {  
  4.             camera.stopPreview();  
  5.             preview.setCamera(null);  
  6.             camera.release();  
  7.             camera = null;  
  8.             preview.setNull();  
  9.         }  
  10.         super.onPause();  
  11.   
  12.     }  

本项目源码(Eclipse版):http://download.csdn.net/download/gao_chun/9084853

注:测试机-------> 小米2A、红米、华为P8、华为荣耀3C,魅蓝note2


附:有些小伙伴经常问手机Gif动画如何制作的,在此也分享下:

动画制作小软件GifMaker:http://download.csdn.net/detail/gao_chun/9077023


注:这代码有些问题,我会在后面贴上最新的优化代码,欢迎继续支持

目录
相关文章
|
1月前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
41 3
|
1月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
86 0
|
3月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
79 2
基于Android P,自定义Android开机动画的方法
|
3月前
|
供应链 物联网 区块链
未来触手可及:探索新兴技术的趋势与应用安卓开发中的自定义视图:从基础到进阶
【8月更文挑战第30天】随着科技的飞速发展,新兴技术如区块链、物联网和虚拟现实正在重塑我们的世界。本文将深入探讨这些技术的发展趋势和应用场景,带你领略未来的可能性。
|
3月前
|
测试技术 Android开发 Python
探索软件测试的艺术:从基础到高级安卓应用开发中的自定义视图
【8月更文挑战第29天】在软件开发的世界中,测试是不可或缺的一环。它如同艺术一般,需要精细的技巧和深厚的知识。本文旨在通过浅显易懂的语言,引领读者从软件测试的基础出发,逐步深入到更复杂的测试策略和工具的使用,最终达到能够独立进行高效测试的水平。我们将一起探索如何通过不同的测试方法来确保软件的质量和性能,就像艺术家通过不同的色彩和笔触来完成一幅画作一样。
|
19天前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
21天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
30 5
|
1月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
2月前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
62 10
|
2月前
|
XML 编解码 Android开发
安卓开发中的自定义视图控件
【9月更文挑战第14天】在安卓开发中,自定义视图控件是一种高级技巧,它可以让开发者根据项目需求创建出独特的用户界面元素。本文将通过一个简单示例,引导你了解如何在安卓项目中实现自定义视图控件,包括创建自定义控件类、处理绘制逻辑以及响应用户交互。无论你是初学者还是有经验的开发者,这篇文章都会为你提供有价值的见解和技巧。
46 3