異常:java.lang.RuntimeException: setParameters failed
Android調(diào)用camera錯(cuò)誤setParameters failed深層解析
真機(jī)測(cè)試報(bào)錯(cuò)ERROR/AndroidRuntime: java.lang.RuntimeException: setParameters failed解決辦法
Android關(guān)閉自定義相機(jī)拍照聲音
android 自定義相機(jī)Camera2
Android提供了Camera來(lái)控制拍照,步驟如下:
(1)調(diào)用Camera的open()方法打開相機(jī)。
(2)調(diào)用Camera的getParameters()獲取拍照參數(shù),該方法返回一個(gè)Cmera.Parameters對(duì)象。
(3)調(diào)用Camera.Parameters對(duì)象對(duì)照相的參數(shù)進(jìn)行設(shè)置。
(4)調(diào)用Camera的setParameters(),并將Camera.Parameters對(duì)象作為參數(shù)傳入,這樣就可以對(duì)拍照進(jìn)行參數(shù)控制,Android2.3.3以后不用設(shè)置。
(5)調(diào)用Camerade的startPreview()的方法開始預(yù)覽取景,在之前需要調(diào)用Camera的setPreviewDisplay(SurfaceHolder holder)設(shè)置使用哪個(gè)SurfaceView來(lái)顯示取得的圖片。
(6)調(diào)用Camera的takePicture()方法進(jìn)行拍照。
(7)程序結(jié)束時(shí),要調(diào)用Camera的stopPreview()方法停止預(yù)覽,并且通過(guò)Camera.release()來(lái)釋放資源。
需要賦予Camera的權(quán)限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.CAMERA"/>
具體代碼:
package com.lyj.camera;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
public class MyCameraActivity extends Activity implements SurfaceHolder.Callback {
private ImageView back, position;//返回和切換前后置攝像頭
private SurfaceView surface;
private ImageButton shutter;//快門
private SurfaceHolder holder;
private Camera camera;//聲明相機(jī)
private String filepath = "";//照片保存路徑
private int cameraPosition = 1;//0代表前置攝像頭,1代表后置攝像頭
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//沒(méi)有標(biāo)題
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//設(shè)置全屏
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照過(guò)程屏幕一直處于高亮
//設(shè)置手機(jī)屏幕朝向,一共有7種
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
//SCREEN_ORIENTATION_BEHIND: 繼承Activity堆棧中當(dāng)前Activity下面的那個(gè)Activity的方向
//SCREEN_ORIENTATION_LANDSCAPE: 橫屏(風(fēng)景照) ,顯示時(shí)寬度大于高度
//SCREEN_ORIENTATION_PORTRAIT: 豎屏 (肖像照) , 顯示時(shí)高度大于寬度
//SCREEN_ORIENTATION_SENSOR 由重力感應(yīng)器來(lái)決定屏幕的朝向,它取決于用戶如何持有設(shè)備,當(dāng)設(shè)備被旋轉(zhuǎn)時(shí)方向會(huì)隨之在橫屏與豎屏之間變化
//SCREEN_ORIENTATION_NOSENSOR: 忽略物理感應(yīng)器——即顯示方向與物理感應(yīng)器無(wú)關(guān),不管用戶如何旋轉(zhuǎn)設(shè)備顯示方向都不會(huì)隨著改變("unspecified"設(shè)置除外)
//SCREEN_ORIENTATION_UNSPECIFIED: 未指定,此為默認(rèn)值,由Android系統(tǒng)自己選擇適當(dāng)?shù)姆较颍x擇策略視具體設(shè)備的配置情況而定,因此不同的設(shè)備會(huì)有不同的方向選擇
//SCREEN_ORIENTATION_USER: 用戶當(dāng)前的首選方向
setContentView(R.layout.main);
back = (ImageView) findViewById(R.id.camera_back);
position = (ImageView) findViewById(R.id.camera_position);
surface = (SurfaceView) findViewById(R.id.camera_surface);
shutter = (ImageButton) findViewById(R.id.camera_shutter);
holder = surface.getHolder();//獲得句柄
holder.addCallback(this);//添加回調(diào)
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//surfaceview不維護(hù)自己的緩沖區(qū),等待屏幕渲染引擎將內(nèi)容推送到用戶面前
//設(shè)置監(jiān)聽(tīng)
back.setOnClickListener(listener);
position.setOnClickListener(listener);
shutter.setOnClickListener(listener);
}
//響應(yīng)點(diǎn)擊事件
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.camera_back:
//返回
MyCameraActivity.this.finish();
break;
case R.id.camera_position:
//切換前后攝像頭
int cameraCount = 0;
CameraInfo cameraInfo = new CameraInfo();
cameraCount = Camera.getNumberOfCameras();//得到攝像頭的個(gè)數(shù)
for(int i = 0; i < cameraCount; i ) {
Camera.getCameraInfo(i, cameraInfo);//得到每一個(gè)攝像頭的信息
if(cameraPosition == 1) {
//現(xiàn)在是后置,變更為前置
if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表攝像頭的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置
camera.stopPreview();//停掉原來(lái)攝像頭的預(yù)覽
camera.release();//釋放資源
camera = null;//取消原來(lái)攝像頭
camera = Camera.open(i);//打開當(dāng)前選中的攝像頭
try {
camera.setPreviewDisplay(holder);//通過(guò)surfaceview顯示取景畫面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();//開始預(yù)覽
cameraPosition = 0;
break;
}
} else {
//現(xiàn)在是前置, 變更為后置
if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表攝像頭的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置
camera.stopPreview();//停掉原來(lái)攝像頭的預(yù)覽
camera.release();//釋放資源
camera = null;//取消原來(lái)攝像頭
camera = Camera.open(i);//打開當(dāng)前選中的攝像頭
try {
camera.setPreviewDisplay(holder);//通過(guò)surfaceview顯示取景畫面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();//開始預(yù)覽
cameraPosition = 1;
break;
}
}
}
break;
case R.id.camera_shutter:
//快門
camera.autoFocus(new AutoFocusCallback() {//自動(dòng)對(duì)焦
@Override
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
if(success) {
//設(shè)置參數(shù),并拍照
Parameters params = camera.getParameters();
params.setPictureFormat(PixelFormat.JPEG);//圖片格式
params.setPreviewSize(800, 480);//圖片大小
camera.setParameters(params);//將參數(shù)設(shè)置到我的camera
camera.takePicture(null, null, jpeg);//將拍攝到的照片給自定義的對(duì)象
}
}
});
break;
}
}
};
/*surfaceHolder他是系統(tǒng)提供的一個(gè)用來(lái)設(shè)置surfaceView的一個(gè)對(duì)象,而它通過(guò)surfaceView.getHolder()這個(gè)方法來(lái)獲得。
Camera提供一個(gè)setPreviewDisplay(SurfaceHolder)的方法來(lái)連接*/
//SurfaceHolder.Callback,這是個(gè)holder用來(lái)顯示surfaceView 數(shù)據(jù)的接口,他必須實(shí)現(xiàn)以下3個(gè)方法
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
//當(dāng)surfaceview創(chuàng)建時(shí)開啟相機(jī)
if(camera == null) {
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);//通過(guò)surfaceview顯示取景畫面
camera.startPreview();//開始預(yù)覽
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
//當(dāng)surfaceview關(guān)閉時(shí),關(guān)閉預(yù)覽并釋放資源
camera.stopPreview();
camera.release();
camera = null;
holder = null;
surface = null;
}
//創(chuàng)建jpeg圖片回調(diào)數(shù)據(jù)對(duì)象
PictureCallback jpeg = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
//自定義文件保存路徑 以拍攝時(shí)間區(qū)分命名
filepath = "/sdcard/Messages/MyPictures/" new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) ".jpg";
File file = new File(filepath);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮的流里面
bos.flush();// 刷新此緩沖區(qū)的輸出流
bos.close();// 關(guān)閉此輸出流并釋放與此流有關(guān)的所有系統(tǒng)資源
camera.stopPreview();//關(guān)閉預(yù)覽 處理數(shù)據(jù)
camera.startPreview();//數(shù)據(jù)處理完后繼續(xù)開始預(yù)覽
bitmap.recycle();//回收bitmap空間
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}