问题起源
由于最近项目中调用系统拍照遇到了问题(在调取系统相机后,由于内存不足会将app杀掉导致相机拍照返回后,出现白屏),故后来自己定义相机实现拍照功能。但是发现有setParameters failed的问题。
分析
先看现象,是在切换为前置摄像头的时候,点击屏幕实现聚焦的时候崩溃,而且后置摄像头没有问题。那么先看代码:
private void focusOnRect(Rect rect) {
if (getCamera() != null) {
Camera.Parameters parameters = getCamera().getParameters(); // 先获取当前相机的参数配置对象
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
if (parameters.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(rect, 1000));
parameters.setFocusAreas(focusAreas);
}
getCamera().setParameters(parameters);
getCamera().autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
Log.i(TAG, "autoFocusCallback success:" + success);
}
});
}
}
猜想1:是surfaceView设置的预览宽度和高度不支持,于是将原来动态获取高宽的方法改成定死的1080 720 ,发现还是不行。
猜想2:是点击画面的时候,算的聚焦的Rect上下左右超出边界后来通过日志发现都是在-1000~1000之内,也没有问题
猜想3:是否是聚焦的方法写的有问题,于是找了很多第三方写的聚焦方法,如下
public void handleFocus(MotionEvent event, FrameLayout preview) {
int viewWidth = preview.getWidth();
int viewHeight = preview.getHeight();
Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f, viewWidth, viewHeight);
Camera camera = getCamera();
camera.cancelAutoFocus();
Camera.Parameters params = camera.getParameters();
if (params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<>();
focusAreas.add(new Camera.Area(focusRect, 800));
params.setFocusAreas(focusAreas);
} else {
Log.i(TAG, "focus areas not supported");
}
final String currentFocusMode = params.getFocusMode();
params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
camera.setParameters(params);
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
Camera.Parameters params = camera.getParameters();
params.setFocusMode(currentFocusMode);
camera.setParameters(params);
}
});
}
private static Rect calculateTapArea(float x, float y, float coefficient, int width, int
height) {
float focusAreaSize = 300;
int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
int centerX = (int) (x / width * 2000 - 1000);
int centerY = (int) (y / height * 2000 - 1000);
int halfAreaSize = areaSize / 2;
RectF rectF = new RectF(clamp(centerX - halfAreaSize, -1000, 1000)
, clamp(centerY - halfAreaSize, -1000, 1000)
, clamp(centerX + halfAreaSize, -1000, 1000)
, clamp(centerY + halfAreaSize, -1000, 1000));
return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right)
, Math.round(rectF.bottom));
}
private static int clamp(int x, int min, int max) {
if (x > max) {
return max;
}
if (x < min) {
return min;
}
return x;
}
发现还是一样会崩溃。说明也不是这个问题
猜想4:是否是采用的Camera api已经废弃了,高的安卓版本不支持了
后来发现还是其他开源的demo 也是采用Camera api 但是没有出现此问题,
解决
突然看到一个人的博客上的一句话,“应该是Parameters设置了有问题”。这句话点醒我了,于是我找到关键代码。看到底对Parameters做了什么?
最后发现只有2处
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(rect, 1000));
parameters.setFocusAreas(focusAreas);
最终定位发现 有些手机的前置摄像头的getSupportedFocusModes 只有fixed模式,然而我设置了Camera.Parameters.FOCUS_MODE_AUTO。最后更改如下,在设置聚焦模式的时候,检查是否支持,另外 在聚焦完成之后,将原先的聚焦模式再设置回来
private void focusOnRect(Rect rect) {
if (getCamera() != null) {
Camera.Parameters parameters = getCamera().getParameters(); // 先获取当前相机的参数配置对象
// parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 设置聚焦模式
final String currentFocusMode = parameters.getFocusMode();
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
//如果包含相应对焦模式 才设置此对焦模式,否则不变
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
Log.i(TAG, "parameters.getFocusMode() : " + currentFocusMode);
Log.i(TAG,
"parameters.getSupportedFocusModes() : " + parameters.getSupportedFocusModes());
if (parameters.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(rect, 1000));
parameters.setFocusAreas(focusAreas);
}
// getCamera().cancelAutoFocus(); // 先要取消掉进程中所有的聚焦功能
getCamera().setParameters(parameters);
getCamera().autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
Log.i(TAG, "autoFocusCallback success:" + success);
Camera.Parameters params = camera.getParameters();
params.setFocusMode(currentFocusMode);
camera.setParameters(params);
}
});
}
}
问题解决! 如果有不对的地方 欢迎指正~