2013-07-27 3 views
0

Моя основная деятельность представляет собой предварительный просмотр камеры. Когда я поворачиваю телефон, приложение закрывается. В журналах я вижу, что surfaceCreated() и surfaceChanged() никогда не вызываются после вращения, затем вызывается main onStop().surfaceCreated() не вызывается после вращения

Телефоны Motorola и Samsung демонстрируют такое же поведение. Другие действия в моем приложении выдержат вращение, как ожидалось.

Я думал, что проблема может быть устаревшей ссылкой предварительного просмотра, но журналы показывают новый держатель и экземпляры предварительного просмотра.

  1. Почему не вызываются обратные вызовы держателя после вращения?
  2. Могу ли я заставить их называться?

Вход фрагмент

07-27 08:32:12.093: I/MainActivity(21285): 
07-27 08:32:12.093: I/MainActivity(21285): ***********STARTING APP***************** 
     07-27 08:32:12.093: I/MainActivity(21285): onCreate 
07-27 08:32:12.093: I/MainActivity(21285): 
07-27 08:32:12.289: I/StackOPreview(21285): in constructor 
07-27 08:32:12.289: V/StackOPreview(21285): holder: [email protected] 
07-27 08:32:12.289: V/StackOPreview(21285): this: [email protected] 
07-27 08:32:12.296: I/MainActivity(21285): onCreate finished 
07-27 08:32:12.296: I/MainActivity(21285): 
07-27 08:32:12.296: I/MainActivity(21285): ||||||||||||||||||| ON RESUME ||||||||||||||||||| 
07-27 08:32:12.296: I/MainActivity(21285): 
07-27 08:32:12.367: I/StackOPreview(21285): surfaceCreated 
07-27 08:32:12.375: I/StackOPreview(21285): view width: 540 height: 960 
07-27 08:32:12.375: I/StackOPreview(21285): portrait mode so rotate camera preview 
07-27 08:32:12.382: I/CameraSettings(21285): retreiving portrait orientation 
07-27 08:32:12.382: I/SettingsCP(21285): starting Settings ContentProvider query 
07-27 08:32:12.421: I/SettingsCP(21285): got 1 settings 
07-27 08:32:12.421: I/CameraSettings(21285): retrieved portrait orientation= 90 
07-27 08:32:12.429: I/CameraSettings(21285): 
07-27 08:32:12.429: I/CameraSettings(21285): retreiving portrait rotation 
07-27 08:32:12.429: I/SettingsCP(21285): starting Settings ContentProvider query 
07-27 08:32:12.429: I/SettingsCP(21285): got 1 settings 
07-27 08:32:12.429: I/CameraSettings(21285): retrieved portrait rotation= 90 
07-27 08:32:12.429: I/CameraSettings(21285): 
07-27 08:32:12.468: I/StackOPreview(21285): setting View measured dimensions to width: 540 height: 960 
07-27 08:32:12.468: I/StackOPreview(21285): optimal preview width: 1920 height: 1080 
07-27 08:32:13.929: I/StackOPreview(21285): surfaceChanged 
07-27 08:32:14.085: I/StackOPreview(21285): view width: 540 height: 960 
07-27 08:32:14.085: I/StackOPreview(21285): portrait mode so rotate camera preview 
07-27 08:32:14.085: I/CameraSettings(21285): retreiving portrait orientation 
07-27 08:32:14.085: I/SettingsCP(21285): starting Settings ContentProvider query 
07-27 08:32:14.085: I/SettingsCP(21285): got 1 settings 
07-27 08:32:14.085: I/CameraSettings(21285): retrieved portrait orientation= 90 
07-27 08:32:14.085: I/CameraSettings(21285): 
07-27 08:32:14.085: I/CameraSettings(21285): retreiving portrait rotation 
07-27 08:32:14.085: I/SettingsCP(21285): starting Settings ContentProvider query 
07-27 08:32:14.085: I/SettingsCP(21285): got 1 settings 
07-27 08:32:14.093: I/CameraSettings(21285): retrieved portrait rotation= 90 
07-27 08:32:14.093: I/CameraSettings(21285): 
07-27 08:32:14.101: I/StackOPreview(21285): setting View measured dimensions to width: 540 height: 960 
07-27 08:32:14.101: I/StackOPreview(21285): optimal preview width: 1920 height: 1080 
07-27 08:32:27.109: I/MainActivity(21285): 
07-27 08:32:27.109: I/MainActivity(21285): ||||||||||||||||||| ON PAUSE ||||||||||||||||||| 
07-27 08:32:27.109: I/MainActivity(21285): 
07-27 08:32:27.757: I/StackOPreview(21285): onPause 
07-27 08:32:27.757: I/MainActivity(21285): releasing camera in onPause 
07-27 08:32:27.757: E/MainActivity(21285): onStop 
07-27 08:32:27.757: I/MainActivity(21285): 
07-27 08:32:27.757: I/MainActivity(21285): ||||||||||||||||||| ON STOP ||||||||||||||||||| 

ЗДЕСЬ ПОВОРОТ START

07-27 08:32:27.757: I/MainActivity(21285): 
07-27 08:32:27.789: I/MainActivity(21285): 
07-27 08:32:27.789: I/MainActivity(21285): ***********STARTING APP***************** 
07-27 08:32:27.789: I/MainActivity(21285): onCreate 
07-27 08:32:27.789: I/MainActivity(21285): 
07-27 08:32:27.890: I/StackOPreview(21285): in constructor 
07-27 08:32:27.890: V/StackOPreview(21285): holder: [email protected] 
07-27 08:32:27.890: V/StackOPreview(21285): this: [email protected] 
07-27 08:32:27.898: I/MainActivity(21285): onCreate finished 
07-27 08:32:27.898: I/MainActivity(21285): 
07-27 08:32:27.898: I/MainActivity(21285): ||||||||||||||||||| ON RESUME ||||||||||||||||||| 


HERE IS WHERE surfaceCreated SHOULD BE CALLED 

07-27 08:32:27.898: I/MainActivity(21285): 
07-27 08:32:27.945: I/MainActivity(21285): 
07-27 08:32:27.945: I/MainActivity(21285): ||||||||||||||||||| ON PAUSE ||||||||||||||||||| 
07-27 08:32:27.945: I/MainActivity(21285): 
07-27 08:32:27.968: I/StackOPreview(21285): onPause 
07-27 08:32:27.968: I/MainActivity(21285): releasing camera in onPause 
07-27 08:32:28.562: E/MainActivity(21285): onStop 

Main вызывается Launcher

public class MainActivity extends Activity implements Constants 

{ 

    private static final String TAG = "MainActivity"; 

    // CameraView variables 
    Camera camera; 

    boolean isPreviewRunning = false; 

    StackOPreview preview; 

    PhotoSaver photoSaver = null; 

    LayoutInflater controlInflater = null; 

    // first rear facing camera 
    int defaultCameraId; 

    // can't put big byte array in an Intent so keep a reference. This may not 
    // survive pauses. 
    private static byte[] currentPhoto = null; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Log.i(TAG, " "); 
     Log.i(TAG, "***********STARTING APP*****************"); 

     Log.i(TAG, "onCreate"); 

     Log.i(TAG, " "); 

     getWindow().setFormat(PixelFormat.TRANSLUCENT); 

     requestWindowFeature(Window.FEATURE_NO_TITLE); 

     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
       WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     // Find the total number of cameras available 
     int numberOfCameras = Camera.getNumberOfCameras(); 

     // Find the ID of the default camera. This assumes the FACING BACK 
     // camera is default. probably burns us sometime. 
     CameraInfo cameraInfo = new CameraInfo(); 
     for (int i = 0; i < numberOfCameras; i++) { 
      Camera.getCameraInfo(i, cameraInfo); 
      if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { 
       defaultCameraId = i; 
      } 
     } 

     camera = Camera.open(defaultCameraId); 
     preview = new StackOPreview(this, camera); 
     setContentView(preview); 

     Log.i(TAG, "onCreate finished"); 

    } 

    protected void onResume() { 

     super.onResume(); 

     Log.i(TAG, " "); 
     Log.i(TAG, "||||||||||||||||||| ON RESUME |||||||||||||||||||"); 
     Log.i(TAG, " "); 

     if (camera == null) { 
      // camera is rarely null in onResume. Either app was destroyed then 
      // recreated because a long time passed, or app was just paused and 
      // camera is still valid. 
      camera = Camera.open(defaultCameraId); 

      // July 24, 2013 sometimes preview is black - suspect it doesn't 
      // have a camera 
      preview.onResume(camera); 

      Log.i(TAG, "OPENING camera in onResume"); 
     } 

    } 

    protected void onPause() { 
     super.onPause(); 

     Log.i(TAG, " "); 
     Log.i(TAG, "||||||||||||||||||| ON PAUSE |||||||||||||||||||"); 
     Log.i(TAG, " "); 

     // Release camera when activity paused 
     if (camera != null) { 
      camera.stopPreview(); 
      camera.release(); 
      camera = null; 

      preview.onPause(); 

      Log.i(TAG, " releasing camera in onPause"); 
     } 

     // close the database 
     Context context = getApplicationContext(); 
     DatabaseHelper databaseHelper = DatabaseHelper.getInstance(context); 
     databaseHelper.close(); 
    } 

    protected void onStop() { 
     Log.e(TAG, "onStop"); 
     super.onStop(); 

     Log.i(TAG, " "); 
     Log.i(TAG, "||||||||||||||||||| ON STOP |||||||||||||||||||"); 
     Log.i(TAG, " "); 

     // close the database 
     Context context = getApplicationContext(); 
     DatabaseHelper databaseHelper = DatabaseHelper.getInstance(context); 
     databaseHelper.close(); 

     finish(); 
    } 

    /** takes the picture */ 
    public void onClick(View arg0) { 
     Log.e(TAG, "in CameraView.onClick"); 
     camera.takePicture(null, null, photoSaver); 

    } 

    /** 
    * @return the currentPhoto 
    */ 
    public static byte[] getCurrentPhoto() { 
     return currentPhoto; 
    } 

    /** 
    * @param currentPhoto 
    *   the currentPhoto to set 
    */ 
    public void setCurrentPhoto(byte[] currentPhoto) { 
     this.currentPhoto = currentPhoto; 
    } 
    } 

Предварительный код:

public class StackOPreview extends SurfaceView implements 
    SurfaceHolder.Callback { 

private SurfaceHolder mHolder; 
public Camera mCamera; 

private static boolean DEBUGGING = true; 
private static final String LOG_TAG = "StackOPreview"; 
private static final String CAMERA_PARAM_ORIENTATION = "orientation"; 
private static final String CAMERA_PARAM_LANDSCAPE = "landscape"; 
private static final String CAMERA_PARAM_PORTRAIT = "portrait"; 
protected Activity mActivity; 

protected List<Camera.Size> previewSizeList = null; 

protected Camera.Size previewSize = null; 

public StackOPreview(Context context, Camera camera) { 
    super(context); 

    Log.i(LOG_TAG,"in constructor"); 

    mActivity = (Activity) context; 
    mCamera = camera; 

    // Install a SurfaceHolder.Callback so we get notified when the 
    // underlying surface is created and destroyed. 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 

    Log.v(LOG_TAG,"holder: "+mHolder); 
    Log.v(LOG_TAG,"this: "+ this); 

    // deprecated setting, but required on Android versions prior to 3.0 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

} 

public void surfaceCreated(SurfaceHolder holder) { 
    Log.i(LOG_TAG, "surfaceCreated"); 
    // The Surface has been created, now tell the camera where to draw the 
    // preview. 
    try { 

     if (mCamera != null) { 

      setRotationAndResolution(); 

      mCamera.setPreviewDisplay(holder); 
      mCamera.startPreview(); 

     } else { 
      Log.d(LOG_TAG, " camera is null"); 
     } 
    } catch (IOException e) { 
     Log.d("CameraView", 
       "Error setting camera preview: " + e.getMessage()); 
    } 
} 

public void surfaceDestroyed(SurfaceHolder holder) { 
    Log.i(LOG_TAG, "surfaceDestroyed"); 
    // empty. Take care of releasing the Camera preview in your activity. 
} 

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    Log.i(LOG_TAG, "surfaceChanged"); 
    // If your preview can change or rotate, take care of those events here. 
    // Make sure to stop the preview before resizing or reformatting it. 

    if (mHolder.getSurface() == null) { 
     Log.d(LOG_TAG, " mHolder is null"); 
     // preview surface does not exist 
     return; 
    } 

    if (mCamera == null) { 
     Log.d(LOG_TAG, " camera is null"); 

     return; 
    } 

    // stop preview before making changes 
    try { 
     mCamera.stopPreview(); 
    } catch (Exception e) { 
     // ignore: tried to stop a non-existent preview 
     Log.e(LOG_TAG, "failed to stopPreview because " + e, e); 
    } 

    // start preview with new settings 
    try { 
     setRotationAndResolution(); 

     mCamera.setPreviewDisplay(mHolder); 
     mCamera.startPreview(); 

    } catch (Exception e) { 
     Log.d("CameraView", "Error starting camera preview: " + e, e); 
    } 
} 

public void onPause() { 
    Log.i(LOG_TAG, "onPause"); 
    if (null == mCamera) { 
     return; 
    } 

    mCamera = null; 

    // try releasing 
    mHolder.removeCallback(this); 
} 

// added July 24 2013. 
/** 
* Rarely called because camera is rarely null in MainActivity's onResume(). 
* Either app was destroyed then recreated because a long time passed, or 
* app was just paused and camera is still valid. Occasionally I see a black 
* screen after sleeping for a while so I added this method to try to fix 
* it. 
*/ 
public void onResume(Camera camera) { 
    Log.i(LOG_TAG, "onResume"); 
    mCamera = camera; 
} 

private void setRotationAndResolution() { 
    final int width = getWidth(); 
    final int height = getHeight(); 

    Log.i(LOG_TAG, "view width: " + width + " height: " + height); 

    if (height > width) { 
     // PORTRAIT 

     Log.i(LOG_TAG, "portrait mode so rotate camera preview"); 

     Context context = getContext(); 

     int portraitOrientation = CameraSettings 
       .getPortraitPreviewOrientation(context); 

     int portraitRotation = CameraSettings 
       .getPortraitPictureRotation(context); 

     try { 
      // THis line fixed the preview orientation. seems to 
      // have to be called before setPreviewDisplay() 
      mCamera.setDisplayOrientation(portraitOrientation); 

      Camera.Parameters parameters = mCamera.getParameters(); 

      // this line fixes the recorded image's orientation 
      parameters.setRotation(portraitRotation); 

      previewSize = getOptimalPreviewSize(); 

      parameters 
        .setPreviewSize(previewSize.width, previewSize.height); 

      mCamera.setParameters(parameters); 
     } catch (Exception e) { 
      Log.e(LOG_TAG, "portrait preview settings failed: " + e, e); 
      Log.e(LOG_TAG, " orientation: " + portraitOrientation); 
      Log.e(LOG_TAG, " rotation: " + portraitRotation); 
      Log.e(LOG_TAG, " "); 
     } 

    } else { 
     // LANDSCAPE 

     Log.i(LOG_TAG, " landscape mode"); 

     int landscapeOrientation = 0; 
     int landscapeRotation = 0; 

     try { 
      Context context = getContext(); 
      landscapeOrientation = CameraSettings 
        .getLandscapePreviewOrientation(context); 
      landscapeRotation = CameraSettings 
        .getLandscapePictureRotation(context); 

      mCamera.setDisplayOrientation(landscapeOrientation); 

      previewSize = getOptimalPreviewSize(); 

      // THis line fixed the preview orientation. seems to 
      // have to be called before setPreviewDisplay() 
      mCamera.setDisplayOrientation(landscapeOrientation); 

      Camera.Parameters parameters = mCamera.getParameters(); 

      // this line fixes the recorded image's orientation 
      parameters.setRotation(landscapeRotation); 

      parameters 
        .setPreviewSize(previewSize.width, previewSize.height); 

      mCamera.setParameters(parameters); 
     } catch (Exception e) { 
      Log.e(LOG_TAG, "landscape preview settings failed: " + e, e); 
      Log.e(LOG_TAG, " orientation: " + landscapeOrientation); 
      Log.e(LOG_TAG, " rotation: " + landscapeRotation); 
      Log.e(LOG_TAG, " "); 
     } 
    } 

} 

private Size getOptimalPreviewSize() { 

    // if list isn't retrieved yet, then get it 
    if (previewSizeList == null) { 
     previewSizeList = mCamera.getParameters() 
       .getSupportedPreviewSizes(); 

    } 

    int width = getWidth(); 

    int height = getHeight(); 

    Log.i(LOG_TAG, "setting View measured dimensions to width: " + width 
      + " height: " + height); 

    final double ASPECT_TOLERANCE = 0.1; 
    double targetRatio = (double) width/height; 

    Size optimalSize = null; 
    double minDiff = Double.MAX_VALUE; 

    int targetHeight = height; 

    // Try to find an size match aspect ratio and size 
    for (Size size : previewSizeList) { 
     //Log.v(LOG_TAG, " width: " + size.width + " height: " 
      // + size.height); 

     double ratio = (double) size.width/size.height; 
     if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) 
      continue; 
     if (Math.abs(size.height - targetHeight) < minDiff) { 
      optimalSize = size; 
      minDiff = Math.abs(size.height - targetHeight); 
     } 
    } 

    // Cannot find the one match the aspect ratio, ignore the requirement 
    if (optimalSize == null) { 
     minDiff = Double.MAX_VALUE; 
     for (Size size : previewSizeList) { 
      if (Math.abs(size.height - targetHeight) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 
    } 

    Log.i(LOG_TAG, "optimal preview width: " + optimalSize.width 
      + " height: " + optimalSize.height); 

    return optimalSize; 
} 

}

+0

У Android 2.3.3 есть эта проблема. Android 4.1.2 не перезапускает приложение на Galaxy S3, поэтому проблема не возникает. –

+0

добавлен держатель уведомление PReview's onResume public void onResume (Camera camera) { \t \t Log.i (LOG_TAG, "onResume"); \t \t mCamera = камера; \t \t mHolder = getHolder(); \t \t mHolder.addCallback (this); \t \t mHolder.setType (SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); \t \t \t \t Log.v (LOG_TAG, "держатель:" + mHolder); \t \t Log.v (LOG_TAG, "this:" + this); \t \t} –

+0

добавление уведомления владельца не повлияло –

ответ

1

Я решил проблему, используя отзыв от Марка Мерфи в Commonsware. Я перевел Preview create to onResume() в основное действие. Кроме того, я удалил вызов finish() в onStop(). Вот работа onCreate() и onResume() в MainActivity:

public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Find the total number of cameras available 
     int numberOfCameras = Camera.getNumberOfCameras(); 

     // Find the ID of the default camera. This assumes the FACING BACK 
     // camera is default. probably burns us sometime. 
     CameraInfo cameraInfo = new CameraInfo(); 
     for (int i = 0; i < numberOfCameras; i++) { 
      Camera.getCameraInfo(i, cameraInfo); 
      if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { 
       defaultCameraId = i; 
      } 
     } 
} 

    protected void onResume() { 

     super.onResume(); 

     Log.i(TAG, " "); 
     Log.i(TAG, "||||||||||||||||||| ON RESUME |||||||||||||||||||"); 
     Log.i(TAG, " "); 

     getWindow().setFormat(PixelFormat.TRANSLUCENT); 

     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
       WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     camera = Camera.open(defaultCameraId); 
     preview = new StackOPreview(this, camera); 
     setContentView(preview); 

     // *** new control layer that contains the TakePicture button *** 
     controlInflater = LayoutInflater.from(getBaseContext()); 

     viewControl = controlInflater.inflate(R.layout.control_preview, null); 

     LayoutParams layoutParamsControl = new LayoutParams(
       LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 

     this.addContentView(viewControl, layoutParamsControl); 

     photoSaver = new PhotoSaver(this); 

     buttonTakePicture = (ImageButton) findViewById(R.id.takepicture); 

     buttonTakePicture.setOnClickListener(new Button.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       Log.v(TAG, 
         "in Take Picture button on click, launching photSaver"); 
       camera.takePicture(null, null, photoSaver); 
      } 
     }); 

     // table button 
     Button tableButton = (Button) findViewById(R.id.display_table); 

     TableButtonListener tableButtonListener = new TableButtonListener(this); 
     tableButton.setOnClickListener(tableButtonListener); 
    } 
Смежные вопросы