studio open manejo example developer custom camara android camera surfaceview

manejo - open camera android developer



¿Cómo se relacionan las devoluciones de llamada de SurfaceHolder con el ciclo de vida de la actividad? (5)

Aquí hay una solución alternativa para todos los métodos de devolución de llamada, que pueden estar todos sujetos al mismo comportamiento de orden de evento indefinido con ciclo de actividad. A menos que vaya a inspeccionar todo el código de Android para cada devolución de llamada que usa para determinar el desencadenante de origen y quién controla las implementaciones y espera que la base de código no cambie en el futuro, ¿puede decirse realmente que el orden de eventos entre retrollamadas? y los eventos del ciclo de vida de la actividad podrían estar garantizados.

En este momento, estas interacciones de orden normalmente se pueden denominar comportamientos indefinidos, con fines de desarrollo.

Lo mejor sería manejar siempre correctamente este comportamiento indefinido, de modo que nunca sea un problema en primer lugar, asegurándose de que las órdenes sean un comportamiento definido.

Mi Sony Xperia, por ejemplo, mientras duerme, hace ciclos en mi aplicación actual, destruyendo la aplicación y luego reiniciándola y poniéndola en pausa, créalo o no.

No sé cuántas pruebas de comportamiento de ordenación de eventos proporciona Google en su SDK como implementación de prueba especial para entornos de host, pero definitivamente deben esforzarse para garantizar que los comportamientos de las órdenes de eventos estén bloqueados por ser bastante estrictos en el importar.

https://code.google.com/p/android/issues/detail?id=214171&sort=-opened&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened

importar android.util.Log; importar android.util.SparseArray;

/ ** * Creado por woliver el 24/06/2016. * * Entorno de host de Android, dicta un Ciclo de vida de la actividad para OnCreate, onStart, onResume, onPause, onStop, onDestory, * donde estamos obligados a liberar memoria y maneja para que otras aplicaciones la usen. * Cuando se reanuda, a veces se nos solicita volver a vincular y activar estos elementos con otros objetos. * Normalmente, estos otros objetos proporcionan métodos de devolución de llamada desde el entorno del host que proporcionan * un onCreated y onDestroy, en los que solo podemos enlazar a este objeto desde OnCreated y y loose * out bind onDestory. * Este tipo de métodos de devolución de llamada, tiempo de ejecución para ejecutar es controlado por nuestro entorno de host * y no garantiza que el comportamiento / orden de ejecución del Ciclo de vida de la actividad y estos métodos de devolución de llamada * permanezca constante. * Para fines de desarrollo, las interacciones y el orden de ejecución se pueden llamar técnicamente indefinidos *, ya que depende del implementador de la implementación del host, samsung, sony, htc. * * Consulte el siguiente documento para desarrolladores: https://developer.android.com/reference/android/app/Activity.html * Cita: * Si una actividad está completamente oscurecida por otra actividad, se detiene. Todavía conserva toda la información de estado * y miembro, sin embargo, ya no es visible para el usuario, por lo que su ventana * está oculta y el sistema la eliminará a menudo cuando se necesite memoria en otro lugar. * EndQuato: * * Si la actividad no está oculta, no se habrán llamado a las devoluciones de llamada que uno habría esperado que realizara el sistema host *, como los métodos OnCreate y OnDestory que interactúan con la devolución de llamada de SurfaceView. * Esto significa que tendrá que detener el objeto que se ha vinculado a SurfaceView, como una cámara * en pausa, y nunca volverá a vincular el objeto, ya que nunca se llamará a la devolución de llamada OnCreate. * * /

public abstract class WaitAllActiveExecuter<Size> { private SparseArray<Boolean> mReferancesState = null; // Use a dictionary and not just a counter, as hosted code // environment implementer may make a mistake and then may double executes things. private int mAllActiveCount = 0; private String mContextStr; public WaitAllActiveExecuter(String contextStr, int... identifiers) { mReferancesState = new SparseArray<Boolean>(identifiers.length); mContextStr = contextStr; for (int i = 0; i < identifiers.length; i++) mReferancesState.put(identifiers[i], false); } public void ActiveState(int identifier) { Boolean state = mReferancesState.get(identifier); if (state == null) { // Typically panic here referance was not registered here. throw new IllegalStateException(mContextStr + "ActiveState: Identifier not found ''" + identifier + "''"); } else if(state == false){ mReferancesState.put(identifier, true); mAllActiveCount++; if (mAllActiveCount == mReferancesState.size()) RunActive(); } else { Log.e(mContextStr, "ActivateState: called to many times for identifier ''" + identifier + "''"); // Typically panic here and output a log message. } } public void DeactiveState(int identifier) { Boolean state = mReferancesState.get(identifier); if (state == null) { // Typically panic here referance was not registered here. throw new IllegalStateException(mContextStr + "DeActiveState: Identifier not found ''" + identifier + "''"); } else if(state == true){ if (mAllActiveCount == mReferancesState.size()) RunDeActive(); mReferancesState.put(identifier, false); mAllActiveCount--; } else { Log.e(mContextStr,"DeActiveState: State called to many times for identifier''" + identifier + "''"); // Typically panic here and output a log message. } } private void RunActive() { Log.v(mContextStr, "Executing Activate"); ExecuterActive(); } private void RunDeActive() { Log.v(mContextStr, "Executing DeActivate"); ExecuterDeActive(); } abstract public void ExecuterActive(); abstract public void ExecuterDeActive(); }

Ejemplo de Implementación y uso de clase, que trata sobre el comportamiento indefinido de los implementadores de entornos host de Android.

private final int mBCTSV_SurfaceViewIdentifier = 1; private final int mBCTSV_CameraIdentifier = 2; private WaitAllActiveExecuter mBindCameraToSurfaceView = new WaitAllActiveExecuter("BindCameraToSurfaceViewe", new int[]{mBCTSV_SurfaceViewIdentifier, mBCTSV_CameraIdentifier}) { @Override public void ExecuterActive() { // Open a handle to the camera, if not open yet and the SurfaceView is already intialized. if (mCamera == null) { mCamera = Camera.open(mCameraIDUsed); if (mCamera == null) throw new RuntimeException("Camera could not open"); // Look at reducing the calls in the following two methods, some this is unessary. setDefaultCameraParameters(mCamera); setPreviewSizesForCameraFromSurfaceHolder(getSurfaceHolderForCameraPreview()); } // Bind the Camera to the SurfaceView. try { mCamera.startPreview(); mCamera.setPreviewDisplay(getSurfaceHolderForCameraPreview()); } catch (IOException e) { e.printStackTrace(); ExecuterDeActive(); throw new RuntimeException("Camera preview could not be set"); } } @Override public void ExecuterDeActive() { if ( mCamera != null ) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } }; @Override protected void onPause() { mBindCameraToSurfaceView.DeactiveState(mBCTSV_CameraIdentifier); Log.v(LOG_TAG, "Activity Paused - After Super"); } @Override public void onResume() { mBindCameraToSurfaceView.ActiveState(mBCTSV_CameraIdentifier); } private class SurfaceHolderCallback implements SurfaceHolder.Callback { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.v(LOG_TAG, "Surface Changed"); } public void surfaceCreated(SurfaceHolder surfaceHolder) { Log.v(LOG_TAG, "Surface Created"); mBindCameraToSurfaceView.ActiveState(mBCTSV_SurfaceViewIdentifier); } public void surfaceDestroyed(SurfaceHolder arg0) { Log.v(LOG_TAG, "Surface Destoryed"); mBindCameraToSurfaceView.DeactiveState(mBCTSV_SurfaceViewIdentifier); } }

He intentado implementar una aplicación que requiere una vista previa de la cámara en una superficie. Cuando veo las cosas, los ciclos de vida de actividad y superficie constan de los siguientes estados:

  1. La primera vez que inicio mi actividad: onResume()->onSurfaceCreated()->onSurfaceChanged()
  2. Cuando salgo de mi actividad: onPause()->onSurfaceDestroyed()

En este esquema, puedo hacer las llamadas correspondientes como abrir / soltar la cámara e iniciar / detener la vista previa en onPause/onResume y onSurfaceCreated()/onSurfaceDestroyed() .

Funciona bien, a menos que bloquee la pantalla. Cuando lance la aplicación, bloqueo la pantalla y la desbloqueo más tarde. Veo:

onPause() - y nada más después de que la pantalla está bloqueada - entonces onResume() después del desbloqueo - y no hay devoluciones de llamada en la superficie después de eso. En realidad, onResume() se onResume() después de que se presiona el botón de encendido y la pantalla está encendida, pero la pantalla de bloqueo todavía está activa, por lo tanto, es antes de que la actividad se vuelva incluso visible.

Con este esquema, aparece una pantalla negra después del desbloqueo y no se llaman devoluciones de llamada en la superficie.

Aquí hay un fragmento de código que no implica el trabajo real con la cámara, sino las SurfaceHolder llamada de SurfaceHolder . El problema anterior se reproduce incluso con este código en mi teléfono (las devoluciones de llamada se realizan en una secuencia normal cuando presiona el botón "Atrás", pero faltan cuando bloquea la pantalla):

class Preview extends SurfaceView implements SurfaceHolder.Callback { private static final String tag= "Preview"; public Preview(Context context) { super(context); Log.d(tag, "Preview()"); SurfaceHolder holder = getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { Log.d(tag, "surfaceCreated"); } public void surfaceDestroyed(SurfaceHolder holder) { Log.d(tag, "surfaceDestroyed"); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.d(tag, "surfaceChanged"); } }

¿Alguna idea sobre por qué la superficie no se destruye después de detener la actividad? Además, ¿cómo manejas el ciclo de vida de la cámara en tales casos?


Gracias a ambas respuestas anteriores, pude hacer que la vista previa de mi cámara funcionara claramente mientras retrocedía desde el fondo o desde la pantalla de bloqueo.

Como se mencionó en @ e7fendy, la devolución de llamada de SurfaceView no se ejecutará mientras esté en el bloqueo de pantalla, ya que la vista de la superficie aún está visible para el sistema.

Por lo tanto, como @validcat aconsejó, llamando a preview.setVisibility(View.VISIBLE); y preview.setVisibility(View.GONE); en respectivamente OnPause () y onResume () obligarán a la vista de superficie a retransmitirse y lo llamarán callbacks.

Para entonces, la solución de @ emrys57 más estas dos llamadas a métodos de visibilidad anteriores harán que la cámara de vista previa funcione claramente :)

Así que solo puedo dar +1 a cada uno de ustedes como todos se lo merecieron;)


Otra solución simple que funciona bien: para cambiar la visibilidad de la superficie de vista previa.

private SurfaceView preview;

la vista previa es init en el método onCreate . En el método onResume establece View.VISIBLE para la superficie de vista previa:

@Override public void onResume() { preview.setVisibility(View.VISIBLE); super.onResume(); }

y, respectivamente, en onPause establecer la visibilidad de View.GONE :

@Override public void onPause() { super.onPause(); preview.setVisibility(View.GONE); stopPreviewAndFreeCamera(); //stop and release camera }


SurfaceHolder.Callback está relacionado con su superficie.

Es la actividad en la pantalla? Si es así, no habrá SurfaceHolder.Callback, porque la Superficie aún está en la pantalla.

Para controlar cualquier SurfaceView, puede manejarlo en OnPause / onResume solamente. Para SurfaceHolder.Callback, puede usarlo si la superficie se cambia (creada, cambiada de tamaño y destruida), como inicializar OpenGL cuando se trata de SurfaceCreated, y destruir OpenGL cuando se destruye la superficie, etc.


Editar: si el targetSDK es mayor que 10, al poner la aplicación en modo de suspensión se onPause llamadas onPause y onStop . Source

Miré el ciclo de vida de Activity y SurfaceView en una pequeña aplicación de cámara en mi teléfono Gingerbread. Usted es completamente correcto; la superficie no se destruye cuando se presiona el botón de encendido para poner el teléfono en modo de suspensión. Cuando el teléfono se va a dormir, la actividad se realiza en onPause . (Y no lo hace onStop ). Lo hace onResume cuando el teléfono se onResume y, como usted señala, lo hace mientras la pantalla de bloqueo sigue siendo visible y acepta entradas, lo cual es un poco extraño. Cuando hago que la Actividad sea invisible presionando el botón de Inicio, la Actividad hace tanto onPause como onStop . Algo causa una devolución de llamada a la surfaceDestroyed en este caso entre el final de onPause y el inicio de onStop . No es muy obvio, pero parece muy consistente.

Cuando se presiona el botón de encendido para dormir el teléfono, a menos que se haga algo explícitamente para detenerlo, ¡la cámara sigue funcionando! Si hago que la cámara realice una devolución de llamada por imagen para cada fotograma de vista previa, con un Log.d () allí, las declaraciones de registro siguen apareciendo mientras el teléfono pretende dormir. Creo que es muy astuto .

Como otra confusión, los callbacks a surfaceCreated y surfaceChanged ocurren después de onResume en la actividad, si se está creando la superficie.

Como regla general, administro la cámara en la clase que implementa las devoluciones de llamada de SurfaceHolder.

class Preview extends SurfaceView implements SurfaceHolder.Callback { private boolean previewIsRunning; private Camera camera; public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); // ... // but do not start the preview here! } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // set preview size etc here ... then myStartPreview(); } public void surfaceDestroyed(SurfaceHolder holder) { myStopPreview(); camera.release(); camera = null; } // safe call to start the preview // if this is called in onResume, the surface might not have been created yet // so check that the camera has been set up too. public void myStartPreview() { if (!previewIsRunning && (camera != null)) { camera.startPreview(); previewIsRunning = true; } } // same for stopping the preview public void myStopPreview() { if (previewIsRunning && (camera != null)) { camera.stopPreview(); previewIsRunning = false; } } }

y luego en la Actividad:

@Override public void onResume() { preview.myStartPreview(); // restart preview after awake from phone sleeping super.onResume(); } @Override public void onPause() { preview.myStopPreview(); // stop preview in case phone is going to sleep super.onPause(); }

y eso parece funcionar bien para mí. Los eventos de rotación hacen que la actividad se destruya y se vuelva a crear, lo que hace que SurfaceView se destruya y recree también.