Camera.open () que bloquea el hilo de la interfaz de usuario

He mirado todos los artículos de SO que podría encontrar en esto, pero ninguna de las soluciones de trabajo para mí.

Cuando se llama Camera.open (), hay un retardo de 3 segundos (dar o recibir) donde el hilo de interfaz de usuario está bloqueado. He intentado poner eso en un hilo de fondo. Estoy utilizando actualmente la solución encontrada aquí (pegada abajo) pero el método de la "espera" es síncrono así que bloquea el hilo de la interfaz de usuario también.

Lo que estoy tratando de hacer es cargar este fragmento, mostrar un giro de progreso hasta que la cámara está bien para ir, luego mostrar la cámara en la pantalla, pero este retraso me está matando y no puedo encontrar ninguna solución realmente buena en eso.

Mi fragmento:

public class BarcodeFinderFragment extends Fragment implements View.OnClickListener, Camera.AutoFocusCallback, Camera.PreviewCallback { private static final String CAMERA_THREAD_NAME = "CAMERA_THREAD_NAME"; private Camera mCamera; private CamViewFinder mPreview; private Handler autoFocusHandler; private boolean previewing = true; private Button noScan; private Button noBarcode; private FrameLayout preview; private BarcodeFinderCallback callBack; private ImageScanner scanner; private CameraHandlerThread mThread = null; private BarcodeFinderCallback dummyCallback = new BarcodeFinderCallback() { @Override public void onNoScanClicked() { } @Override public void onNoBarcodeClicked() { } @Override public void finishActivity() { } @Override public void setActivityResult(Bundle bundle) { } @Override public void showProgressDialog(boolean showProgress) { } }; public static BarcodeFinderFragment newInstance() { return new BarcodeFinderFragment(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { callBack = (BarcodeFinderActivity) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener"); } } @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_barcode_finder, container, false); noScan = (Button) view.findViewById(R.id.btnNoScan); noBarcode = (Button) view.findViewById(R.id.btnNobarcode); preview = (FrameLayout) view.findViewById(R.id.cameraPreview); noScan.setOnClickListener(this); noBarcode.setOnClickListener(this); return view; } @Override public void onResume() { super.onResume(); autoFocusHandler = new Handler(); //Instance barcode scanner scanner = new ImageScanner(); scanner.setConfig(0, Config.X_DENSITY, 3); scanner.setConfig(0, Config.Y_DENSITY, 3); openCamera(); mPreview = new CamViewFinder(getActivity(), mCamera, BarcodeFinderFragment.this, BarcodeFinderFragment.this); preview.addView(mPreview); callBack.showProgressDialog(false); } private void getCamera() { mCamera = null; try { mCamera = Camera.open(); } catch (final Exception e) { Log.d("BarcodeFinderFragment", e.toString()); } } private void openCamera() { if (mThread == null) mThread = new CameraHandlerThread(CAMERA_THREAD_NAME); synchronized (mThread) { mThread.openCamera(); } } @Override public void onPause() { super.onPause(); releaseCamera(); } @Override public void onDetach() { super.onDetach(); callBack = dummyCallback; } private Runnable doAutoFocus() { return new Runnable() { @Override public void run() { if (previewing) { mCamera.autoFocus(BarcodeFinderFragment.this); } } }; } private void releaseCamera() { if (mCamera != null) { previewing = false; mCamera.stopPreview(); mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } callBack.finishActivity(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnNoScan: callBack.onNoScanClicked(); break; case R.id.btnNobarcode: callBack.onNoBarcodeClicked(); break; } } @Override public void onAutoFocus(boolean success, Camera camera) { autoFocusHandler.postDelayed(doAutoFocus(), 1000); } @Override public void onPreviewFrame(byte[] data, Camera camera) { final Camera.Parameters parameters = camera.getParameters(); final Camera.Size size = parameters.getPreviewSize(); final Image barcode = new Image(size.width, size.height, "Y800"); barcode.setData(data); final int result = scanner.scanImage(barcode); if (result != 0) { previewing = false; mCamera.setPreviewCallback(null); mCamera.stopPreview(); final SymbolSet syms = scanner.getResults(); for (final Symbol sym : syms) { final Bundle bundle = new Bundle(); bundle.putString("result", sym.getData()); bundle.putString("codeType", "" + sym.getType()); callBack.setActivityResult(bundle); } } } public interface BarcodeFinderCallback { void onNoScanClicked(); void onNoBarcodeClicked(); void finishActivity(); void setActivityResult(Bundle bundle); void showProgressDialog(boolean showProgress); } private class CameraHandlerThread extends HandlerThread { Handler mHandler = null; public CameraHandlerThread(String name) { super(name); callBack.showProgressDialog(true); start(); mHandler = new Handler(getLooper()); } synchronized void notifyCameraOpened() { notify(); } void openCamera() { mHandler.post(new Runnable() { @Override public void run() { getCamera(); notifyCameraOpened(); } }); try { wait(); } catch (InterruptedException e) { Log.d("BarcodeFinderFragment", "wait was interrupted"); } } } } 

ACTUALIZAR

Gracias a MeetTitan, pude conseguir este funcionamiento muy suavemente guardando todo en el hilo de fondo y fijando a la interfaz de usuario cuando era necesario. Aquí está el código de trabajo para cualquiera que lo necesite en el futuro 🙂

 public class BarcodeFinderFragment extends Fragment implements View.OnClickListener { private static final String CAMERA_THREAD_NAME = "CAMERA_THREAD_NAME"; private Camera mCamera; private CamViewFinder mPreview; private Handler autoFocusHandler; private FrameLayout preview; private ImageScanner scanner; private boolean previewing = true; private CameraHandlerThread mThread = null; private BarcodeFinderCallback callBack; private BarcodeFinderCallback dummyCallback = new BarcodeFinderCallback() { @Override public void onNoScanClicked() { } @Override public void onNoBarcodeClicked() { } @Override public void finishActivity() { } @Override public void setActivityResult(int resultCode, Bundle bundle) { } @Override public void showProgressDialog(boolean showProgress) { } }; public static BarcodeFinderFragment newInstance() { return new BarcodeFinderFragment(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { callBack = (BarcodeFinderActivity) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement BarcodeFinderCallback"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_barcode_finder, container, false); Button noScan = (Button) view.findViewById(R.id.btnNoScan); Button noBarcode = (Button) view.findViewById(R.id.btnNobarcode); preview = (FrameLayout) view.findViewById(R.id.cameraPreview); noScan.setOnClickListener(this); noBarcode.setOnClickListener(this); return view; } @Override public void onResume() { super.onResume(); autoFocusHandler = new Handler(); //Instance barcode scanner scanner = new ImageScanner(); scanner.setConfig(0, Config.X_DENSITY, 3); scanner.setConfig(0, Config.Y_DENSITY, 3); callBack.showProgressDialog(true); openCamera(); } private void openCamera() { if (mThread == null) { try { mThread = new CameraHandlerThread(CAMERA_THREAD_NAME); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (mThread) { mThread.openCamera(); } } @Override public void onPause() { super.onPause(); releaseCamera(); if (mThread != null && mThread.isAlive()) mThread.interrupt(); } @Override public void onDetach() { super.onDetach(); callBack = dummyCallback; } private void releaseCamera() { if (mCamera != null) { previewing = false; mCamera.stopPreview(); mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } callBack.finishActivity(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnNoScan: callBack.onNoScanClicked(); break; case R.id.btnNobarcode: callBack.onNoBarcodeClicked(); break; } } public interface BarcodeFinderCallback { void onNoScanClicked(); void onNoBarcodeClicked(); void finishActivity(); void setActivityResult(int resultCode, Bundle bundle); void showProgressDialog(boolean showProgress); } private class CameraHandlerThread extends HandlerThread implements Camera.AutoFocusCallback, Camera.PreviewCallback { Handler mHandler = null; public CameraHandlerThread(String name) throws InterruptedException { super(name); callBack.showProgressDialog(true); start(); mHandler = new Handler(getLooper()); } void openCamera() { mHandler.post(new Runnable() { @Override public void run() { mCamera = null; try { mCamera = Camera.open(); } catch (final Exception e) { Log.d("BarcodeFinderFragment", e.toString()); callBack.setActivityResult(Activity.RESULT_CANCELED, null); interrupt(); } notifyCameraOpened(); getActivity().runOnUiThread(new Runnable() { @Override public void run() { mPreview = new CamViewFinder(getActivity(), mCamera, CameraHandlerThread.this, CameraHandlerThread.this); preview.addView(mPreview); new Handler().postDelayed(new Runnable() { @Override public void run() { callBack.showProgressDialog(false); } }, 500); } }); } }); } synchronized void notifyCameraOpened() { notify(); } @Override public void onAutoFocus(boolean success, Camera camera) { autoFocusHandler.postDelayed(new Runnable() { @Override public void run() { if (previewing) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { mCamera.autoFocus(CameraHandlerThread.this); } }); } } }, 1000); } @Override public void onPreviewFrame(byte[] data, Camera camera) { final Camera.Parameters parameters = camera.getParameters(); final Camera.Size size = parameters.getPreviewSize(); final Image barcode = new Image(size.width, size.height, "Y800"); barcode.setData(data); final int result = scanner.scanImage(barcode); if (result != 0) { previewing = false; mCamera.setPreviewCallback(null); mCamera.stopPreview(); final SymbolSet syms = scanner.getResults(); for (final Symbol sym : syms) { final Bundle bundle = new Bundle(); bundle.putString("result", sym.getData()); bundle.putString("codeType", "" + sym.getType()); getActivity().runOnUiThread(new Runnable() { @Override public void run() { callBack.setActivityResult(Activity.RESULT_OK, bundle); } }); } } } } } 

¿No podrías continuar tu hilo y llamar a los grupos de comandos ui junto con el método yourContext.runOnUiThread() ? A continuación, el fondo cualquier código de bloqueo, esperar a que la cámara esté lista, y actualizar el ui desde el hilo de fondo.

Por ejemplo:

 private class CameraHandlerThread extends ... { public void run() { getCamera(); yourContext.runOnUiThread(new Runnable(){ public void run() { ... } }); } } 

Entonces usted puede simplemente new CameraHandlerThread().start();

  • Se detiene la demostración de la API de la cámara SDK de Android
  • Forzar la resolución de la cámara en Android
  • Necesita un ejemplo de tomar una imagen con MonoDroid y MVVMCross
  • Obtener ruta y nombre de archivo del resultado de la intención de la cámara
  • ¿Cómo puedo encontrar la carpeta de imágenes de la cámara de un teléfono Android?
  • Cómo cambiar la cámara de la parte delantera a la parte posterior y posterior a la parte delantera en el botón haga clic en android
  • Matriz int a la textura opengl en android
  • RuntimeException utilizando Camera.open ()
  • Descripción de la matriz de proyección libGDX
  • Abrir la cámara por defecto en SurfaceView y grabar con cámara frontal
  • Configuración de la API de la cámara Android en ISO?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.