Ответ 1
Использовать SurfaceHolder.Callback → surfaceCreated, чтобы знать, когда вы можете запустить AutoFocus. Если поверхностный держатель не создан (длился некоторое время), автофокусировка завершится с ошибкой.
Я пробовал все, но я все еще не могу решить эту проблему.
Я использую функцию камеры в приложении, и все работает отлично, за исключением автофокуса. Когда я вызываю autoFocus(), он генерирует исключение, и я не могу понять, почему. Я запускаю код на Desire HD.
код:
@Override
protected void onStart() {
super.onStart();
//grab seurface view and callback
cameraView = (CameraSurfaceView) findViewById(R.id.cameraView);
try{
camera = Camera.open();
cameraView.setCamera(camera);
//release previous autofocus and assign new one
camera.cancelAutoFocus();
camera.autoFocus(new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
}});
}
catch (Exception e) {
//had an issue accessing the camera prompt user
//TODO create user prompt
e.printStackTrace();
}
}
Трассировка стека:
01-11 16:09:38.456: W/System.err(26546): java.lang.RuntimeException: autoFocus failed
01-11 16:09:38.456: W/System.err(26546): at android.hardware.Camera.native_autoFocus(Native Method)
01-11 16:09:38.456: W/System.err(26546): at android.hardware.Camera.autoFocus(Camera.java:680)
01-11 16:09:38.456: W/System.err(26546): at com.myapp.MyActivity.onStart(BarcodeScannerActivity.java:57)
01-11 16:09:38.466: W/System.err(26546): at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1201)
01-11 16:09:38.466: W/System.err(26546): at android.app.Activity.performStart(Activity.java:3955)
01-11 16:09:38.466: W/System.err(26546): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1845)
01-11 16:09:38.466: W/System.err(26546): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1893)
01-11 16:09:38.466: W/System.err(26546): at android.app.ActivityThread.access$1500(ActivityThread.java:135)
01-11 16:09:38.466: W/System.err(26546): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1054)
01-11 16:09:38.466: W/System.err(26546): at android.os.Handler.dispatchMessage(Handler.java:99)
01-11 16:09:38.466: W/System.err(26546): at android.os.Looper.loop(Looper.java:150)
01-11 16:09:38.476: W/System.err(26546): at android.app.ActivityThread.main(ActivityThread.java:4385)
01-11 16:09:38.476: W/System.err(26546): at java.lang.reflect.Method.invokeNative(Native Method)
01-11 16:09:38.476: W/System.err(26546): at java.lang.reflect.Method.invoke(Method.java:507)
01-11 16:09:38.476: W/System.err(26546): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
01-11 16:09:38.476: W/System.err(26546): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
01-11 16:09:38.476: W/System.err(26546): at dalvik.system.NativeStart.main(Native Method)
Использовать SurfaceHolder.Callback → surfaceCreated, чтобы знать, когда вы можете запустить AutoFocus. Если поверхностный держатель не создан (длился некоторое время), автофокусировка завершится с ошибкой.
Возможно, вы захотите убедиться, что телефон поддерживает автофокусировку. Это довольно легко проверить:
Camera.Parameters p = mCamera.getParameters();
List<String> focusModes = p.getSupportedFocusModes();
if(focusModes != null && focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
//Phone supports autofocus!
}
else {
//Phone does not support autofocus!
}
Я предлагаю два решения, которые сработали для меня. 1) Остановите и возобновите работу камеры. Я делаю это, вызывая эти методы onPause и onResume, также в середине камеры Preview, где я сканирую QR-коды в своем приложении:
public void stopCamera(){
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mPreviewing = false;
}
public void rethrottleCamera(){
updateViews(); //Updates my Layouts
mPreviewing = true;
mCamera.startPreview();
mCamera.setPreviewCallback(previewCb);
mCamera.autoFocus(autoFocusCB);
}
2) Очень сложно, но работал как магия! Убедитесь, что вы вызываете автофокусировку ПОСЛЕ получения поверхности предварительного просмотра. Для этого запустите Autofocus с задержкой в 200 мс, чтобы выиграть время для создания поверхности. Установите это, нажав ctrl + clic над объявлением объекта CameraPreview, например:
CameraPreview my_camera;
Найдите метод "public void surfaceChanged" и внесите следующие изменения:
//Add a delay to AUTOFOCUS after mCamera.startpreview();!!:
mCamera.startPreview();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.autoFocus(autoFocusCallback);
}
}, 200); //<-200 millisecond delay
//If you call autofocus right after startPreview, chances are,
//that the previewSurface will have not been created yet,
//and autofocus will fail:
mCamera.startPreview(); //Bad idea!
mCamera.autoFocus(autoFocusCallback); //Bad idea!
Есть много других исправлений, но эти два могут сохранить ваш день.
Я нашел хорошее решение
Поэтому позволяет просто исключить исключение и повторить попытку вызвать автофокусировку на некоторых устройствах (т.е. Sony experia и некоторые другие)
Что такое время задержки между попытками (1 секунда)
я не люблю никаких "волшебных" чисел в коде, поэтому в некоторых случаях это может быть слишком большим или слишком маленьким. Его достаточно для меня)
public void requestAutoFocus(Handler handler, int message) {
if(camera != null && previewing) {
autoFocusCallback.setHandler(handler, message);
scheduleAutoFocus();
}
}
public void safeAutoFocus() {
try {
camera.autoFocus(autoFocusCallback);
} catch (RuntimeException e) {
// Horrible hack to deal with autofocus errors on Sony devices
// See https://github.com/dm77/barcodescanner/issues/7 for example
scheduleAutoFocus(); // wait 1 sec and then do check again
}
}
private void scheduleAutoFocus() {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if(camera != null && previewing) {
safeAutoFocus();
}
}
};
и вот методы начала и остановки
public void startPreview() {
if (camera != null && !previewing) {
camera.startPreview();
camera.autoFocus(autoFocusCallback);
previewing = true;
}
}
public void stopPreview() {
if(camera != null && previewing) {
try {
camera.cancelAutoFocus();
if(!useOneShotPreviewCallback) {
camera.setPreviewCallback(null);
}
camera.stopPreview();
previewCallback.setHandler(null, 0);
autoFocusCallback.setHandler(null, 0);
previewing = false;
} catch(Exception e) {
Log.e(TAG, e.toString(), e);
}
}
}
Убедитесь, что вы вызываете функцию автофокуса после вызова предварительного просмотра. Согласно документации по Android
Этот метод действителен только в том случае, если предварительный просмотр активен (между startPreview() и перед stopPreview()).
Если вы все еще сталкиваетесь с какой-либо ошибкой, попробуйте Rasmus и решение zwebie в том же порядке.
Есть много решений, но это простой, умеренный дешевый вариант, который работал у меня:
try{
mCamera.autoFocus(autoFocusCB); //Or whatever part of code that crashes
}
catch(Exception e){
Log.v("joshtag","THIS PHONE DOES NOT SUPPORT AUTOFOCUS!!"); //a warning, popup, whatever
}
Вуаля! Ловушка деактивирована.