2013-07-27 27 views
0

我的主要活動是呈現相機預覽。當我旋轉手機時,應用程序關閉。在日誌中,我看到surfaceCreated()和surfaceChanged()在旋轉後永遠不會調用,然後調用main的onStop()。surfaceCreated()在旋轉後未調用

摩托羅拉和三星手機表現出相同的行爲。我的應用程序中的其他活動按預期順利進行。

我認爲問題可能是過時的預覽參考,但日誌顯示新的持有者和預覽實例。

  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 ||||||||||||||||||| 

這裏開始旋轉

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 

主要由發射

稱爲
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的onResume添加持卡人通知 public void onResume(Camera camera){ \t \t Log.i(LOG_TAG,「onResume」); \t \t mCamera = camera; \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,「holder:」+ mHolder); \t \t Log.v(LOG_TAG,「this:」+ this); \t \t} –

+0

添加持有人通知沒有影響 –

回答

1

我用Commonsware的Mark Murphy的提示解決了這個問題。我在主要活動中將預覽創建移動到了onResume()。另外,我刪除了onStop()中的finish()調用。這裏是MainActivity中的onCreate()和onResume():

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); 
    }