玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级。后来随着我自己的使用,越来越发现不出个升级版的demo是不行了。有时候就连我自己用这个demo测一些性能、功能点,用着都不顺手。当初代码是在linux下写的,弄到windows里下全是乱码。还要自己改几分钟才能改好。另外,很多人说不能正常预览,原因是我在布局里把Surfaceview的尺寸写死了。再有就是initCamera()的时候设参数失败,直接黑屏退出,原因也是我把预览尺寸和照片尺寸写死了。再有就是照片变形的问题。为此,今天出一个升级版的demo,争取全面适配所有机型。

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

上图为此次的代码结构,activity包里就是放CameraActivity,日后添加图库浏览功能再加GalleryActivity。为了使Camera的逻辑和界面的UI耦合度降至最低,封装了CameraInterface类,里面操作Camera的打开、预览、拍照、关闭。preview包里是自定义的Surfaceview。在util包里放着CamParaUtil是专门用来设置、打印Camera的PreviewSize、PictureSize、FocusMode的,并能根据Activity传进来的长宽比(主要是16:9 或 4:3两种尺寸)自动寻找适配的PreviewSize和PictureSize,消除变形。默认的是全屏,因为一些手机全屏时,屏幕的长宽比不是16:9或4:3所以在找尺寸时也是存在一些偏差的。其中有个值,就是判断两个float是否相等,这个参数比较关键,里面设的0.03.经我多个手机测试,这个参数是最合适的,否则的话有些奇葩手机得到的尺寸拍出照片变形。下面上源码:

一、布局 activity_camera.xml

  1. <span style="font-family:Comic Sans MS;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context=".CameraActivity" >
  6. <FrameLayout
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content" >
  9. <org.yanzi.camera.preview.CameraSurfaceView
  10. android:id="@+id/camera_surfaceview"
  11. android:layout_width="0dip"
  12. android:layout_height="0dip" />
  13. </FrameLayout>
  14. <ImageButton
  15. android:id="@+id/btn_shutter"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:background="@drawable/btn_shutter_background"
  19. android:layout_alignParentBottom="true"
  20. android:layout_centerHorizontal="true"
  21. android:layout_marginBottom="10dip"/>
  22. </RelativeLayout>
  23. </span>

二、AndroidManifest.xml

  1. <span style="font-family:Comic Sans MS;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="org.yanzi.playcamera"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk
  7. android:minSdkVersion="9"
  8. android:targetSdkVersion="17" />
  9. <!-- 增加文件存储和访问摄像头的权限 -->
  10. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  11. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  12. <uses-permission android:name="android.permission.CAMERA" />
  13. <uses-feature android:name="android.hardware.camera" />
  14. <application
  15. android:allowBackup="true"
  16. android:icon="@drawable/ic_launcher_icon"
  17. android:label="@string/app_name"
  18. android:theme="@style/AppTheme" >
  19. <activity
  20. android:name="org.yanzi.activity.CameraActivity"
  21. android:label="@string/app_name"
  22. android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
  23. android:screenOrientation="portrait">
  24. <intent-filter>
  25. <action android:name="android.intent.action.MAIN" />
  26. <category android:name="android.intent.category.LAUNCHER" />
  27. </intent-filter>
  28. </activity>
  29. </application>
  30. </manifest>
  31. </span>

三、下面是java代码

1、CameraActivity.Java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.activity;
  2. import org.yanzi.camera.CameraInterface;
  3. import org.yanzi.camera.CameraInterface.CamOpenOverCallback;
  4. import org.yanzi.camera.preview.CameraSurfaceView;
  5. import org.yanzi.playcamera.R;
  6. import org.yanzi.util.DisplayUtil;
  7. import android.app.Activity;
  8. import android.graphics.Point;
  9. import android.os.Bundle;
  10. import android.view.Menu;
  11. import android.view.SurfaceHolder;
  12. import android.view.View;
  13. import android.view.View.OnClickListener;
  14. import android.view.ViewGroup.LayoutParams;
  15. import android.widget.ImageButton;
  16. public class CameraActivity extends Activity implements CamOpenOverCallback {
  17. private static final String TAG = "yanzi";
  18. CameraSurfaceView surfaceView = null;
  19. ImageButton shutterBtn;
  20. float previewRate = -1f;
  21. @Override
  22. protected void onCreate(Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. Thread openThread = new Thread(){
  25. @Override
  26. public void run() {
  27. // TODO Auto-generated method stub
  28. CameraInterface.getInstance().doOpenCamera(CameraActivity.this);
  29. }
  30. };
  31. openThread.start();
  32. setContentView(R.layout.activity_camera);
  33. initUI();
  34. initViewParams();
  35. shutterBtn.setOnClickListener(new BtnListeners());
  36. }
  37. @Override
  38. public boolean onCreateOptionsMenu(Menu menu) {
  39. // Inflate the menu; this adds items to the action bar if it is present.
  40. getMenuInflater().inflate(R.menu.camera, menu);
  41. return true;
  42. }
  43. private void initUI(){
  44. surfaceView = (CameraSurfaceView)findViewById(R.id.camera_surfaceview);
  45. shutterBtn = (ImageButton)findViewById(R.id.btn_shutter);
  46. }
  47. private void initViewParams(){
  48. LayoutParams params = surfaceView.getLayoutParams();
  49. Point p = DisplayUtil.getScreenMetrics(this);
  50. params.width = p.x;
  51. params.height = p.y;
  52. previewRate = DisplayUtil.getScreenRate(this); //默认全屏的比例预览
  53. surfaceView.setLayoutParams(params);
  54. //手动设置拍照ImageButton的大小为120dip×120dip,原图片大小是64×64
  55. LayoutParams p2 = shutterBtn.getLayoutParams();
  56. p2.width = DisplayUtil.dip2px(this, 80);
  57. p2.height = DisplayUtil.dip2px(this, 80);;
  58. shutterBtn.setLayoutParams(p2);
  59. }
  60. @Override
  61. public void cameraHasOpened() {
  62. // TODO Auto-generated method stub
  63. SurfaceHolder holder = surfaceView.getSurfaceHolder();
  64. CameraInterface.getInstance().doStartPreview(holder, previewRate);
  65. }
  66. private class BtnListeners implements OnClickListener{
  67. @Override
  68. public void onClick(View v) {
  69. // TODO Auto-generated method stub
  70. switch(v.getId()){
  71. case R.id.btn_shutter:
  72. CameraInterface.getInstance().doTakePicture();
  73. break;
  74. default:break;
  75. }
  76. }
  77. }
  78. }
  79. </span>

2、CameraInterface.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.camera;
  2. import java.io.IOException;
  3. import java.util.List;
  4. import org.yanzi.util.CamParaUtil;
  5. import org.yanzi.util.FileUtil;
  6. import org.yanzi.util.ImageUtil;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.graphics.PixelFormat;
  10. import android.hardware.Camera;
  11. import android.hardware.Camera.PictureCallback;
  12. import android.hardware.Camera.ShutterCallback;
  13. import android.hardware.Camera.Size;
  14. import android.util.Log;
  15. import android.view.SurfaceHolder;
  16. public class CameraInterface {
  17. private static final String TAG = "yanzi";
  18. private Camera mCamera;
  19. private Camera.Parameters mParams;
  20. private boolean isPreviewing = false;
  21. private float mPreviwRate = -1f;
  22. private static CameraInterface mCameraInterface;
  23. public interface CamOpenOverCallback{
  24. public void cameraHasOpened();
  25. }
  26. private CameraInterface(){
  27. }
  28. public static synchronized CameraInterface getInstance(){
  29. if(mCameraInterface == null){
  30. mCameraInterface = new CameraInterface();
  31. }
  32. return mCameraInterface;
  33. }
  34. /**打开Camera
  35. * @param callback
  36. */
  37. public void doOpenCamera(CamOpenOverCallback callback){
  38. Log.i(TAG, "Camera open....");
  39. mCamera = Camera.open();
  40. Log.i(TAG, "Camera open over....");
  41. callback.cameraHasOpened();
  42. }
  43. /**开启预览
  44. * @param holder
  45. * @param previewRate
  46. */
  47. public void doStartPreview(SurfaceHolder holder, float previewRate){
  48. Log.i(TAG, "doStartPreview...");
  49. if(isPreviewing){
  50. mCamera.stopPreview();
  51. return;
  52. }
  53. if(mCamera != null){
  54. mParams = mCamera.getParameters();
  55. mParams.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式
  56. CamParaUtil.getInstance().printSupportPictureSize(mParams);
  57. CamParaUtil.getInstance().printSupportPreviewSize(mParams);
  58. //设置PreviewSize和PictureSize
  59. Size pictureSize = CamParaUtil.getInstance().getPropPictureSize(
  60. mParams.getSupportedPictureSizes(),previewRate, 800);
  61. mParams.setPictureSize(pictureSize.width, pictureSize.height);
  62. Size previewSize = CamParaUtil.getInstance().getPropPreviewSize(
  63. mParams.getSupportedPreviewSizes(), previewRate, 800);
  64. mParams.setPreviewSize(previewSize.width, previewSize.height);
  65. mCamera.setDisplayOrientation(90);
  66. CamParaUtil.getInstance().printSupportFocusMode(mParams);
  67. List<String> focusModes = mParams.getSupportedFocusModes();
  68. if(focusModes.contains("continuous-video")){
  69. mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
  70. }
  71. mCamera.setParameters(mParams);
  72. try {
  73. mCamera.setPreviewDisplay(holder);
  74. mCamera.startPreview();//开启预览
  75. } catch (IOException e) {
  76. // TODO Auto-generated catch block
  77. e.printStackTrace();
  78. }
  79. isPreviewing = true;
  80. mPreviwRate = previewRate;
  81. mParams = mCamera.getParameters(); //重新get一次
  82. Log.i(TAG, "最终设置:PreviewSize--With = " + mParams.getPreviewSize().width
  83. + "Height = " + mParams.getPreviewSize().height);
  84. Log.i(TAG, "最终设置:PictureSize--With = " + mParams.getPictureSize().width
  85. + "Height = " + mParams.getPictureSize().height);
  86. }
  87. }
  88. /**
  89. * 停止预览,释放Camera
  90. */
  91. public void doStopCamera(){
  92. if(null != mCamera)
  93. {
  94. mCamera.setPreviewCallback(null);
  95. mCamera.stopPreview();
  96. isPreviewing = false;
  97. mPreviwRate = -1f;
  98. mCamera.release();
  99. mCamera = null;
  100. }
  101. }
  102. /**
  103. * 拍照
  104. */
  105. public void doTakePicture(){
  106. if(isPreviewing && (mCamera != null)){
  107. mCamera.takePicture(mShutterCallback, null, mJpegPictureCallback);
  108. }
  109. }
  110. /*为了实现拍照的快门声音及拍照保存照片需要下面三个回调变量*/
  111. ShutterCallback mShutterCallback = new ShutterCallback()
  112. //快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
  113. {
  114. public void onShutter() {
  115. // TODO Auto-generated method stub
  116. Log.i(TAG, "myShutterCallback:onShutter...");
  117. }
  118. };
  119. PictureCallback mRawCallback = new PictureCallback()
  120. // 拍摄的未压缩原数据的回调,可以为null
  121. {
  122. public void onPictureTaken(byte[] data, Camera camera) {
  123. // TODO Auto-generated method stub
  124. Log.i(TAG, "myRawCallback:onPictureTaken...");
  125. }
  126. };
  127. PictureCallback mJpegPictureCallback = new PictureCallback()
  128. //对jpeg图像数据的回调,最重要的一个回调
  129. {
  130. public void onPictureTaken(byte[] data, Camera camera) {
  131. // TODO Auto-generated method stub
  132. Log.i(TAG, "myJpegCallback:onPictureTaken...");
  133. Bitmap b = null;
  134. if(null != data){
  135. b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图
  136. mCamera.stopPreview();
  137. isPreviewing = false;
  138. }
  139. //保存图片到sdcard
  140. if(null != b)
  141. {
  142. //设置FOCUS_MODE_CONTINUOUS_VIDEO)之后,myParam.set("rotation", 90)失效。
  143. //图片竟然不能旋转了,故这里要旋转下
  144. Bitmap rotaBitmap = ImageUtil.getRotateBitmap(b, 90.0f);
  145. FileUtil.saveBitmap(rotaBitmap);
  146. }
  147. //再次进入预览
  148. mCamera.startPreview();
  149. isPreviewing = true;
  150. }
  151. };
  152. }
  153. </span>

3、CameraSurfaceView.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.camera.preview;
  2. import org.yanzi.camera.CameraInterface;
  3. import android.content.Context;
  4. import android.graphics.PixelFormat;
  5. import android.util.AttributeSet;
  6. import android.util.Log;
  7. import android.view.SurfaceHolder;
  8. import android.view.SurfaceView;
  9. public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
  10. private static final String TAG = "yanzi";
  11. CameraInterface mCameraInterface;
  12. Context mContext;
  13. SurfaceHolder mSurfaceHolder;
  14. public CameraSurfaceView(Context context, AttributeSet attrs) {
  15. super(context, attrs);
  16. // TODO Auto-generated constructor stub
  17. mContext = context;
  18. mSurfaceHolder = getHolder();
  19. mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明
  20. mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  21. mSurfaceHolder.addCallback(this);
  22. }
  23. @Override
  24. public void surfaceCreated(SurfaceHolder holder) {
  25. // TODO Auto-generated method stub
  26. Log.i(TAG, "surfaceCreated...");
  27. }
  28. @Override
  29. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  30. int height) {
  31. // TODO Auto-generated method stub
  32. Log.i(TAG, "surfaceChanged...");
  33. }
  34. @Override
  35. public void surfaceDestroyed(SurfaceHolder holder) {
  36. // TODO Auto-generated method stub
  37. Log.i(TAG, "surfaceDestroyed...");
  38. CameraInterface.getInstance().doStopCamera();
  39. }
  40. public SurfaceHolder getSurfaceHolder(){
  41. return mSurfaceHolder;
  42. }
  43. }
  44. </span>

4、CamParaUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import java.util.Collections;
  3. import java.util.Comparator;
  4. import java.util.List;
  5. import android.hardware.Camera;
  6. import android.hardware.Camera.Size;
  7. import android.util.Log;
  8. public class CamParaUtil {
  9. private static final String TAG = "yanzi";
  10. private CameraSizeComparator sizeComparator = new CameraSizeComparator();
  11. private static CamParaUtil myCamPara = null;
  12. private CamParaUtil(){
  13. }
  14. public static CamParaUtil getInstance(){
  15. if(myCamPara == null){
  16. myCamPara = new CamParaUtil();
  17. return myCamPara;
  18. }
  19. else{
  20. return myCamPara;
  21. }
  22. }
  23. public  Size getPropPreviewSize(List<Camera.Size> list, float th, int minWidth){
  24. Collections.sort(list, sizeComparator);
  25. int i = 0;
  26. for(Size s:list){
  27. if((s.width >= minWidth) && equalRate(s, th)){
  28. Log.i(TAG, "PreviewSize:w = " + s.width + "h = " + s.height);
  29. break;
  30. }
  31. i++;
  32. }
  33. if(i == list.size()){
  34. i = 0;//如果没找到,就选最小的size
  35. }
  36. return list.get(i);
  37. }
  38. public Size getPropPictureSize(List<Camera.Size> list, float th, int minWidth){
  39. Collections.sort(list, sizeComparator);
  40. int i = 0;
  41. for(Size s:list){
  42. if((s.width >= minWidth) && equalRate(s, th)){
  43. Log.i(TAG, "PictureSize : w = " + s.width + "h = " + s.height);
  44. break;
  45. }
  46. i++;
  47. }
  48. if(i == list.size()){
  49. i = 0;//如果没找到,就选最小的size
  50. }
  51. return list.get(i);
  52. }
  53. public boolean equalRate(Size s, float rate){
  54. float r = (float)(s.width)/(float)(s.height);
  55. if(Math.abs(r - rate) <= 0.03)
  56. {
  57. return true;
  58. }
  59. else{
  60. return false;
  61. }
  62. }
  63. public  class CameraSizeComparator implements Comparator<Camera.Size>{
  64. public int compare(Size lhs, Size rhs) {
  65. // TODO Auto-generated method stub
  66. if(lhs.width == rhs.width){
  67. return 0;
  68. }
  69. else if(lhs.width > rhs.width){
  70. return 1;
  71. }
  72. else{
  73. return -1;
  74. }
  75. }
  76. }
  77. /**打印支持的previewSizes
  78. * @param params
  79. */
  80. public  void printSupportPreviewSize(Camera.Parameters params){
  81. List<Size> previewSizes = params.getSupportedPreviewSizes();
  82. for(int i=0; i< previewSizes.size(); i++){
  83. Size size = previewSizes.get(i);
  84. Log.i(TAG, "previewSizes:width = "+size.width+" height = "+size.height);
  85. }
  86. }
  87. /**打印支持的pictureSizes
  88. * @param params
  89. */
  90. public  void printSupportPictureSize(Camera.Parameters params){
  91. List<Size> pictureSizes = params.getSupportedPictureSizes();
  92. for(int i=0; i< pictureSizes.size(); i++){
  93. Size size = pictureSizes.get(i);
  94. Log.i(TAG, "pictureSizes:width = "+ size.width
  95. +" height = " + size.height);
  96. }
  97. }
  98. /**打印支持的聚焦模式
  99. * @param params
  100. */
  101. public void printSupportFocusMode(Camera.Parameters params){
  102. List<String> focusModes = params.getSupportedFocusModes();
  103. for(String mode : focusModes){
  104. Log.i(TAG, "focusModes--" + mode);
  105. }
  106. }
  107. }
  108. </span>

5、DisplayUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import android.content.Context;
  3. import android.graphics.Point;
  4. import android.util.DisplayMetrics;
  5. import android.util.Log;
  6. public class DisplayUtil {
  7. private static final String TAG = "DisplayUtil";
  8. /**
  9. * dip转px
  10. * @param context
  11. * @param dipValue
  12. * @return
  13. */
  14. public static int dip2px(Context context, float dipValue){
  15. final float scale = context.getResources().getDisplayMetrics().density;
  16. return (int)(dipValue * scale + 0.5f);
  17. }
  18. /**
  19. * px转dip
  20. * @param context
  21. * @param pxValue
  22. * @return
  23. */
  24. public static int px2dip(Context context, float pxValue){
  25. final float scale = context.getResources().getDisplayMetrics().density;
  26. return (int)(pxValue / scale + 0.5f);
  27. }
  28. /**
  29. * 获取屏幕宽度和高度,单位为px
  30. * @param context
  31. * @return
  32. */
  33. public static Point getScreenMetrics(Context context){
  34. DisplayMetrics dm =context.getResources().getDisplayMetrics();
  35. int w_screen = dm.widthPixels;
  36. int h_screen = dm.heightPixels;
  37. Log.i(TAG, "Screen---Width = " + w_screen + " Height = " + h_screen + " densityDpi = " + dm.densityDpi);
  38. return new Point(w_screen, h_screen);
  39. }
  40. /**
  41. * 获取屏幕长宽比
  42. * @param context
  43. * @return
  44. */
  45. public static float getScreenRate(Context context){
  46. Point P = getScreenMetrics(context);
  47. float H = P.y;
  48. float W = P.x;
  49. return (H/W);
  50. }
  51. }
  52. </span>

6、FileUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import java.io.BufferedOutputStream;
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import android.graphics.Bitmap;
  7. import android.os.Environment;
  8. import android.util.Log;
  9. public class FileUtil {
  10. private static final  String TAG = "FileUtil";
  11. private static final File parentPath = Environment.getExternalStorageDirectory();
  12. private static   String storagePath = "";
  13. private static final String DST_FOLDER_NAME = "PlayCamera";
  14. /**初始化保存路径
  15. * @return
  16. */
  17. private static String initPath(){
  18. if(storagePath.equals("")){
  19. storagePath = parentPath.getAbsolutePath()+"/" + DST_FOLDER_NAME;
  20. File f = new File(storagePath);
  21. if(!f.exists()){
  22. f.mkdir();
  23. }
  24. }
  25. return storagePath;
  26. }
  27. /**保存Bitmap到sdcard
  28. * @param b
  29. */
  30. public static void saveBitmap(Bitmap b){
  31. String path = initPath();
  32. long dataTake = System.currentTimeMillis();
  33. String jpegName = path + "/" + dataTake +".jpg";
  34. Log.i(TAG, "saveBitmap:jpegName = " + jpegName);
  35. try {
  36. FileOutputStream fout = new FileOutputStream(jpegName);
  37. BufferedOutputStream bos = new BufferedOutputStream(fout);
  38. b.compress(Bitmap.CompressFormat.JPEG, 100, bos);
  39. bos.flush();
  40. bos.close();
  41. Log.i(TAG, "saveBitmap成功");
  42. } catch (IOException e) {
  43. // TODO Auto-generated catch block
  44. Log.i(TAG, "saveBitmap:失败");
  45. e.printStackTrace();
  46. }
  47. }
  48. }
  49. </span>

7、ImageUtil.java

  1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.util;
  2. import android.graphics.Bitmap;
  3. import android.graphics.Matrix;
  4. public class ImageUtil {
  5. /**
  6. * 旋转Bitmap
  7. * @param b
  8. * @param rotateDegree
  9. * @return
  10. */
  11. public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree){
  12. Matrix matrix = new Matrix();
  13. matrix.postRotate((float)rotateDegree);
  14. Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
  15. return rotaBitmap;
  16. }
  17. }
  18. </span>

几点说明:

1、包括我之前的博文在内的大量网上链接,都是在Surfaceview create的时候进行打开Camera的操作,在Surfaceview Changed的时候进行开预览。而Surfaceview create的时候一定是在setContentView之后,Surfaceview实例化之后。为了优化开启Camera时间,我再setContentView之前new了一个线程专门去Open Camera。经过测试,但就执行Camera.open()这句话一般需要140ms左右。如果放在主线程里无疑是一种浪费。而在140ms之后,Surfaceview里因为无需触发关于Camera的操作,所以加载的特别快。也就是说Open完后,Surfaceview一定完成了实例化。所以我设置了CamOpenOverCallback回调,在Camera打开完毕后通知Activity立即执行开预览的操作。

2、开预览因为用Surfaceview预览,需传递Surfaceview的SurfaceHolder。

3、CameraInterface是个单例模式,所有关于Camera的流程性操作一律封装在这里面。

4、Activity设置了全屏无标题且强制竖屏,像这种操作能再xml写就不要再java代码里弄。

图片资源上,杂家还真是一番精心挑选,对比了Camera360、相机360、美颜相机,UI上总的来说三个app感觉都很垃圾,都整的太复杂了,图片也不好看。最后勉强用了相机360里的一个button,自己想用PS把按键点击时的图标色彩P亮点,一个没留神,还给P的更暗了色彩。汗,不过按键的对比效果更明显了。日后,会将一些OpenCV4Android的一些小demo都整合到PlayCamera系列。

下为效果图:

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

------------本文系原创,转载请注明作者yanzi1225627

版本号:PlayCamera_V1.0.0[2014-6-22].zip

CSDN下载链接:http://download.csdn.net/detail/yanzi1225627/7540873

百度云盘:

上一篇:微信小程序开发日记——高仿知乎日报(中)


下一篇:我的CPG插件 (什么是CPG,就是跟号称全球唯一C++编写的魔镜是一样的格式的)