建立一个类实现SurfaceHolder.Callback在重载的方法(surfaceCreated ,surfaceChanged ,surfaceDestroyed)里面操作surfaceview
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView sufaceview; private SurfaceHolder holder; private Camera camera; private boolean isPreview = false; private FloatingActionButton fab; private Bitmap bitmap; private Camera.AutoFocusCallback myAutoFocusCallback = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fab = (FloatingActionButton) findViewById(R.id.fab); //拍照的点击事件 fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(isPreview&&camera!=null){ camera.takePicture(new Camera.ShutterCallback() { @Override public void onShutter() { //快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。 Log.i("paizhao","啪啪啪"); } }, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] bytes, Camera camera) { if(null!=bytes){ //解码数组成一张Bitmap图片 bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); //相机停止预览 camera.stopPreview(); isPreview=false; } //构造一个矩形来填充图片 Matrix matrix = new Matrix(); Bitmap rotbitmap = Bitmap.createBitmap(MainActivity.this.bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); if(null!=rotbitmap){ //保存相片 saveBitmap(rotbitmap); } //再次进入预览 camera.startPreview(); isPreview = true; } }); } } }); //自动聚焦变量回调 myAutoFocusCallback = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { // TODO Auto-generated method stub if(success)//success表示对焦成功 { Log.i("tag", "myAutoFocusCallback: success..."); camera.setOneShotPreviewCallback(null); } else { //未对焦成功 Log.i("tag", "myAutoFocusCallback: 失败了..."); } } }; fab.setOnTouchListener(new MyOnTouchListener()); sufaceview = (SurfaceView) findViewById(R.id.sfv); holder = sufaceview.getHolder(); holder.setFormat(PixelFormat.TRANSLUCENT); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//后面有几种类型的解释 } private void saveBitmap(Bitmap rotbitmap) { String savePath = "/mnt/sdcard/xiangjiPhoto/"; File savefile = new File(savePath); if(!savefile.exists()){ savefile.mkdir(); } long data = System.currentTimeMillis(); String jpegName = savePath + data + ".jpg"; try { FileOutputStream fos = new FileOutputStream(jpegName); BufferedOutputStream bos = new BufferedOutputStream(fos); bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos); bos.flush(); bos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { //开启摄像头 camera = Camera.open(); try { camera.setPreviewDisplay(surfaceHolder); } catch (IOException e) { if(null != camera){ camera.release(); camera = null; } e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { initCamera(); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { if(null != camera) { camera.setPreviewCallback(null); /*在启动PreviewCallback时这个必须在前不然退出出错。 这里实际上注释掉也没关系*/ camera.stopPreview(); isPreview = false; camera.release(); camera = null; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } //初始化相机 public void initCamera(){ if(isPreview){ camera.stopPreview(); } if(null != camera){ Camera.Parameters myParam = camera.getParameters(); // //查询屏幕的宽和高 // WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); // Display display = wm.getDefaultDisplay(); // Log.i(tag, "屏幕宽度:"+display.getWidth()+" 屏幕高度:"+display.getHeight()); myParam.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式 // //查询camera支持的picturesize和previewsize // List<Size> pictureSizes = myParam.getSupportedPictureSizes(); // List<Size> previewSizes = myParam.getSupportedPreviewSizes(); // for(int i=0; i<pictureSizes.size(); i++){ // Size size = pictureSizes.get(i); // Log.i(tag, "initCamera:摄像头支持的pictureSizes: width = "+size.width+"height = "+size.height); // } // for(int i=0; i<previewSizes.size(); i++){ // Size size = previewSizes.get(i); // Log.i(tag, "initCamera:摄像头支持的previewSizes: width = "+size.width+"height = "+size.height); // // } //设置大小和方向等参数 myParam.setPictureSize(1280, 960); myParam.setPreviewSize(960, 720); //myParam.set("rotation", 90); camera.setDisplayOrientation(90); myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); camera.setParameters(myParam); camera.startPreview(); camera.autoFocus(myAutoFocusCallback); isPreview = true; } } /*为了使图片按钮按下和弹起状态不同,采用过滤颜色的方法.按下的时候让图片颜色变淡*/ public class MyOnTouchListener implements View.OnTouchListener { public final float[] BT_SELECTED=new float[] { 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 0, 0, 1, 0 }; public final float[] BT_NOT_SELECTED=new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }; public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub if(event.getAction() == MotionEvent.ACTION_DOWN){ v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_SELECTED)); v.setBackgroundDrawable(v.getBackground()); } else if(event.getAction() == MotionEvent.ACTION_UP){ v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_NOT_SELECTED)); v.setBackgroundDrawable(v.getBackground()); } return false; } } } SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface SURFACE_TYPE_GPU:适用于GPU加速的Surface SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。