Lors du développement d'une application d'appareil photo, j'ai rencontré une exception qui ne s'est produite que lorsque je suis passé à une autre application (onPause()
pour mon application).
01-15 17:22:15.017: E/AndroidRuntime(14336): FATAL EXCEPTION: main
01-15 17:22:15.017: E/AndroidRuntime(14336): Java.lang.RuntimeException: Method called after release()
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.hardware.Camera.setPreviewDisplay(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.hardware.Camera.setPreviewDisplay(Camera.Java:357)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.sora.cbir.yuki.image.leaf.CameraPreview.surfaceCreated(CameraPreview.Java:32)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.SurfaceView.updateWindow(SurfaceView.Java:551)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.Java:213)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.View.dispatchWindowVisibilityChanged(View.Java:4075)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.Java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.Java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.Java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.Java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewRoot.performTraversals(ViewRoot.Java:858)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.view.ViewRoot.handleMessage(ViewRoot.Java:1995)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.os.Looper.loop(Looper.Java:150)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Android.app.ActivityThread.main(ActivityThread.Java:4389)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Java.lang.reflect.Method.invokeNative(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): at Java.lang.reflect.Method.invoke(Method.Java:507)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:849)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:607)
01-15 17:22:15.017: E/AndroidRuntime(14336): at dalvik.system.NativeStart.main(Native Method)
J'ai fait des recherches et j'ai découvert que je devais ajouter
mCamera.setPreviewCallback(null);
comme solution de contournement pour la pile de caméras d'Android
ma onPause()
ressemble maintenant à ceci:
@Override
protected void onPause() {
super.onPause();
try
{
// release the camera immediately on pause event
//releaseCamera();
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
catch(Exception e)
{
e.printStackTrace();
}
}
et ma onResume()
:
@Override
protected void onResume()
{
super.onResume();
try
{
mCamera.setPreviewCallback(null);
mCamera = getCameraInstance();
//mCamera.setPreviewCallback(null);
mPreview = new CameraPreview(Imageupload.this, mCamera);//set preview
preview.addView(mPreview);
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
et enfin ma méthode getCameraInstance()
:
public Camera getCameraInstance(){
Camera camera = null;
try {
camera = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
Camera.Parameters parameters = camera.getParameters();
//mPreviewSize = getBestPreviewSize(parameters, wt, ht);
//mPictureSize = getBestPictureSize(parameters, wt, ht);
//Shift W & H => if camera rotates 90 deg
mPreviewSize = getOptimalPreviewSize(parameters, wt, ht); //original => wt,ht
mPictureSize = getOptimalPictureSize(parameters, wt, ht); //original => wt,ht
Log.d("CAMERA", "SCREEN RESOLUTION H: "+ht);
Log.d("CAMERA", "SCREEN RESOLUTION W: "+wt);
Log.d("CAMERA", "PREVIEW RESOLUTION H: "+mPreviewSize.height);
Log.d("CAMERA", "PREVIEW RESOLUTION W: "+mPreviewSize.width);
Log.d("CAMERA", "PICTURE RESOLUTION H: "+mPictureSize.height);
Log.d("CAMERA", "PICTURE RESOLUTION W: "+mPictureSize.width);
//set preview size based on device screen
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//set picture size based on device screen
parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
//set output camera mode
parameters.setPictureFormat(PixelFormat.JPEG);
//set focous mode
parameters.setFocusMode(FOCUS_MODE_AUTO);
//set flash mode
parameters.setFlashMode("auto");
List<int[]> fps = parameters.getSupportedPreviewFpsRange();
//System.out.println("FPS size: " +fps.size());
//System.out.println("MAX FPS:"+(fps.get(fps.size()-1)[1])/1000);
//log min and max camera supported fps
Log.d("CAMERA", "CAMERA MAX FPS: "+(fps.get(fps.size()-1)[1])/1000);
Log.d("CAMERA", "CAMERA MIN FPS: "+(fps.get(fps.size()-1)[0])/1000);
if(camera_fps)
{
parameters.setPreviewFpsRange(fps.get(fps.size()-1)[1], fps.get(fps.size()-1)[1]);
}
//set camera parameters
camera.setParameters(parameters);
Toast.makeText(getApplicationContext(), "Your device are capable of previewing @" + fps.get(fps.size()-1)[1]/1000+"fps!",Toast.LENGTH_SHORT).show();
return camera; // returns null if camera is unavailable
}
des idées pour résoudre le problème?
J'ai le même problème. mCamera.setPreviewCallback(null);
n'a pas aidé. Dans mon activité, j'ai ajouté ceci à releaseCamera
:
mPreview.getHolder().removeCallback(mPreview);
et ça marche maintenant.
La solution @ ookami.kb a également fonctionné pour moi, ainsi que @srunni a commenté.
public void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
mCamera.release();
}
}
J'ai également supprimé la méthode onDestroy.
Les documents indiquent clairement que camera.release()
libère toutes les ressources de la caméra. Après cet appel, la référence de la caméra ne peut plus être utilisée.
Si vous souhaitez réutiliser l'appareil photo, vous devez l'acquérir via une méthode open(int)
.
Tout est décrit dans les camera docs .
Pour reprendre correctement, vous devez procéder comme suit:
@Override
public void onResume() {
super.onResume();
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera initialization
}
}
protected void initializeCamera(){
// Get an instance of Camera Object
mCamera = getCameraInstance();
// create a basic camera preview class that can be included in a View layout.
mPreview=new CameraPreview(this,mCamera);
//add your preview class to the FrameLayout element.
preview.addView(mPreview);
//Trigger capturing an image by calling the Camera.takePicture() method.
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
}
Et aussi juste pour rappeler que dans oncreate () ne rien faire sauf définir l'aperçu FrameLayout et Button captureButton.
@Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
this.getHolder().removeCallback(this);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
Log.e("surfaceDestroyed", "surfaceDestroyed");
}
Et réinitialisez la caméra dans la fonction Reprise.
J'ai mis
mPreview.getHolder().removeCallback(mPreview);
entre.
mCamera.setPreviewCallback(null);
et
mCamera.release();
et cela a fonctionné pour moi.
@Override
protected void onPause() {
super.onPause();
this.saveTextEdits();
try {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
**mPreview.getHolder().removeCallback(mPreview);**
mCamera.release();
mCamera = null;
}catch (Exception e){
}
}
Ajout à la réponse d'Okambi.
C'est la fonction qui gâche tout lorsque vous reprenez:
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
L'essai {} n'attrape pas l'exception levée. À savoir que mCamera n'existe pas, puis lorsqu'il essaie d'appeler setPreviewDisplay (holder), il y a un crash.
Donc, en supprimant le rappel, cette surfaceCreated n'est pas appelée et évite le plantage.
Ceci est TRÈS MAUVAIS DOCUMENTÉ par Google.
Si tu as:
Tentative d'appeler la méthode virtuelle 'void Android.hardware.Camera.setPreviewCallback (Android.hardware.Camera $ PreviewCallback)' sur une référence d'objet null
Je suis d'accord avec @ ookami.kb - mCamera.setPreviewCallback(null);
ne suffit pas, derrière cela ajoutez également ceci:
mCameraView.getHolder().removeCallback(mCameraView);
J'ai rencontré le même problème, je l'ai résolu en - Ajoutant mCamera = null; dans surfaceDestroyed (support SurfaceHolder) méthode de Aperç classe.
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
et - Ajout
camera = Camera.open();
camera.startPreview();
params = camera.getParameters();
preview.setCamera(camera);
dans OnResume () méthode de ma CameraActivity.