Problema con la cámara androide y seguridad de hilo

Como se señaló en la documentación de Android sobre el manejo de la cámara , se recomienda utilizar un hilo separado para abrir la cámara.

Bueno, estoy haciendo eso, pero tengo algunas dificultades:

Para mi objeto de cámara estoy usando una variable de instancia global. Ahora, cuando inicio mi aplicación, creo un subproceso separado en onResume() y realizo todas las inicializaciones para ese objeto de cámara en ese subproceso.

Más tarde, cuando salgo de la aplicación, suelto la cámara en onPause() . Esto funciona muy bien.

Pero el problema es : cuando hice algunas pruebas de estrés y onResume() muy rápido entre onResume() y onPause() (pulsando el botón multitarea excesivamente rápido) mi aplicación se estrelló. La razón era que había un Method called after release() .

Esto tiene sentido ya que es posible que la cámara se puede liberar en onPause() pero al mismo tiempo el subproceso no ha terminado con su inicialización. Por lo tanto, el subproceso intenta realizar una llamada en un objeto de cámara que ya se ha liberado.

Ahora, ¿qué puedo hacer para solucionar esto? Tal vez no utilice un objeto de cámara global? ¿O cómo puedo hacer que este hilo sea seguro?

Tienes unas cuantas opciones.

Opción # 1: sólo toque la Camera desde el hilo de interfaz de usuario.

Esto es bastante sencillo, ya que puede administrar la cámara en onPause() y onResume() . Si desea trabajar con el objeto Camera desde otro subproceso, sólo puede utilizar runOnUiThread() . El problema con este enfoque es que no desea realizar cantidades significativas de trabajo en el subproceso de interfaz de usuario, por lo que tiene que enviar los datos de vista previa en otro lugar.

Este enfoque se utilizó en la actividad "Show + cámara de captura" en Grafika . Hay un comentario largo sobre la gestión de hilos aquí . Tenga en cuenta que la previsualización de la cámara es manejada por el hilo de renderizado GL.

Opción # 2: sólo toque la Camera desde un hilo dedicado de la cámara.

Para que esto funcione, debe enviar mensajes al subproceso cada vez que desee que haga algo con la Camera . Esto se hace más fácilmente con el arreglo usual del Handler y del Looper . El truco es que, al enviar un mensaje, la llamada vuelve inmediatamente . Si envía un mensaje para indicarle al hilo que cierre la cámara desde onPause() , el apagado real de la cámara puede no ocurrir durante un tiempo – y mientras tanto, la actividad está cerrando otras cosas y (si los eventos son onResume() rápidamente) podría estar de vuelta en onResume() antes de que se cierre el apagado. (Sospecho que esto es lo que te está sucediendo.)

Para arrancar y apagar, debe esperar a que se complete. Puede ver un ejemplo de esto en una actividad diferente de Grafika (que no es de cámara), donde espera que el subproceso de procesamiento finalice la inicialización antes de enviarle mensajes. El cierre se sincroniza join() el hilo a medida que se detiene.

Lo más importante a recordar es que sólo puede llamar a los métodos de Camera de un solo hilo – cualquier hilo que se utiliza para abrir la cámara es el único hilo que llega a tocar esa instancia. Después de eso, es un asunto "simple" de gestión de la concurrencia. (Estrictamente hablando, el doc dice que "los métodos de esta clase nunca deben ser llamados a partir de varios subprocesos a la vez ", por lo que puede utilizar múltiples subprocesos si serializa el acceso con cuidado.La forma más fácil de serializar el acceso es hacer sólo las llamadas de un hilo .)

Puede utilizar un indicador booleano para el hilo de la cámara para indicar que la cámara ya no es necesaria (por ejemplo, en el caso de pausa).

Así que su código va a ser algo como esto:

  private boolean isNeeded; private boolean isInitialized; @Override protected void onResume(){ super.onResume(); Thread thread = new Thread(){ @Override public void run(){ // getCamera(); // initializeCamera(); if (isNeeded){ inInitialized = true; // do stuff with Camera } else { //release camera here } } } thread.start(); } protected void onPause(){ super.onPause(); isNeeded = false; if (isInitialized){ //release camera here } } 

Por lo que el hilo de inicialización comprueba si la cámara no es necesaria y suéltela si es así, o inicialice la cámara correctamente y libere la cámara de la onPause.

  • ¿Debo importarme la diferencia entre el hilo principal y el hilo de UI en Lollipop y más allá?
  • Cargar anuncio (adMob) en el subproceso de fondo
  • Dibujo a la lona con la interacción del usuario es un poco laggy
  • Android: Dos instancias de Media Recorder al mismo tiempo
  • TimerTask vs Thread.sleep vs Handler postDelayed - más preciso para llamar a la función cada N milisegundos?
  • Android: Sincronización con el subproceso de procesador de OpenGL
  • Android: Errores de archivo IO
  • Handler.post (runnable) no ejecuta siempre el método run en android
  • ¿Cómo puedo ejecutar esta clase en el hilo de interfaz de usuario?
  • Pruebas de unidad de Android con múltiples subprocesos
  • Compartir recursos entre el contexto de OpenGL en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.