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.
- Guardar las imágenes pulsadas en la carpeta personalizada (Preferentemente interna a la aplicación) en lugar de la galería
- ¿Cómo crear una vista previa de la cámara usando API 21 android?
- Usar la webcam de escritorio en Android AVD
- ¿Hay una manera simple de dar vuelta a la disposición del byte del onPreviewFrame de la cámara en una imagen en androide?
- Cómo escribir datos Exif usando la clase de cámara personalizada en android?
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); } }); } } } } }
- Cómo obtener el directorio predeterminado de la foto hecha por la cámara en android?
- Resumen: Tome una foto utilizando Intención de la cámara y muestre la foto con la orientación correcta (funciona con todos los dispositivos)
- La cámara no se guarda después de tomar la fotografía
- Cámara en Android
- Cámara abierta de Android del botón
- Xamarin.Forms Tome la foto con la cámara muestra la orientación equivocada y se bloquea en el botón Atrás
- Android: onAutoFocus () no está desencadenando en android 4.0 (sandwich de helado) dispositivo virtual
- Flash Torch en Google Nexus 5
¿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();
- Java.lang.IllegalStateException Necesita utilizar un tema Theme.AppCompat (o descendente) con esta actividad
- Android Studio Annotation AbstractProcessor no encontrado