Android 休眠状态对Camera预览的影响

http://blog.csdn.net/sevensundark/article/details/7433177


最近遇到的一个问题,app中有照相功能的预览画面,提供照相功能,在此画面打开的前提下,按关机键使机器进入休眠状态,然后再解除休眠回来,画面中的照相预览部分变成一片漆黑....可如果是app之间的切换(例如,Home键出去,再长按Home键回来)的话没有此问题。

首先打log对比休眠和普通切换App应用,系统做的事情有哪些区别: 休眠--状况A    切换App--状况B

画面打开:

    onCreate->onRestoreInstanceState->onStart->onResume->surfaceCreated->surfaceChanged->surfaceChanged  (surfaceChanged会执行两遍,还没研究为何)

状况A:

   1.进入休眠:onSaveInstanceState->onPause

   2.休眠解除:onResume

状况B:

  1.切出:onSaveInstanceState->onPause->surfaceDestroyed->onStop

  2.切回:onRestart->onStart->onResume->surfaceCreated->surfaceChanged


可以发现,休眠与解除休眠并没有像App切换那样做那么多事,surfaceDestroyed和surfaceChanged都没执行,代码中照相预览需要的Camera对象在surfaceDestroyed中进行释放,在surfaceCreated中进行实例化...

问题集中在上面两种变化状态都会执行的onPause方法里了,果然,onPause里也有对Camera对象进行释放的操作...

原因明了: 进入休眠状态时,执行了camera对象的释放,却在解除休眠状态时没有能执行surfaceCreated进行camera对象的实例化。

于是,删除onpause中释放camera对象的代码,大功告成......


不过,中间试验中发现个有趣的现象,预览用到的控件SurfaceView,取到这个对象,设置它的显示属性能够唤出surfaceDestroyed和surfaceCreated方法的执行。

在onPause中调用setVisibility(View.INVISIBLE)唤出surfaceDestroyed的执行,再在onResume中调用setVisibility(View.VISIBLE)唤出surfaceCreated的执行,同样解决问题。

为啥显示属性会触发到surfaceDestroyed和surfaceCreated,参考了一下源码,大概知道个所以然....

SurfaceView重写了父类(View)的setVisibility方法:

  1. @Override  
  2. public void setVisibility(int visibility) {  
  3.     super.setVisibility(visibility);  
  4.     mViewVisibility = visibility == VISIBLE;  
  5.     mRequestedVisible = mWindowVisibility && mViewVisibility;  
  6.     updateWindow(falsefalse);  
  7. }  

这里设置几个全局boolean变量,例如调用setVisibility(View.INVISIBLE)的时候,mViewVisibility和mRequestedVisible都被赋为false,然后调用updateWindow方法:
  1. private void updateWindow(boolean force, boolean redrawNeeded) {  
  2.           
  3.         ......  
  4.           
  5.         final boolean visibleChanged = mVisible != mRequestedVisible  
  6.                 || mNewSurfaceNeeded;  
  7.         final boolean typeChanged = mType != mRequestedType;  
  8.         if (force || creating || formatChanged || sizeChanged || visibleChanged  
  9.             || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]  
  10.             || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {  
  11.   
  12.             ......  
  13.               
  14.             try {  
  15.                 final boolean visible = mVisible = mRequestedVisible;  
  16.                   
  17.                 ......  
  18.   
  19.                 if (visibleChanged && (!visible || mNewSurfaceNeeded)) {  
  20.                     reportSurfaceDestroyed();  
  21.                 }  
  22.                   
  23.                 ......  
  24.   
  25.                 try {  
  26.                       
  27.                     ......  
  28.   
  29.                     if (visible) {  
  30.                         mDestroyReportNeeded = true;  
  31.   
  32.                         if (visibleChanged) {  
  33.                             mIsCreating = true;  
  34.                             for (SurfaceHolder.Callback c : callbacks) {  
  35.                                 c.surfaceCreated(mSurfaceHolder);  
  36.                             }  
  37.                         }  
  38.                     } else {  
  39.                         ......  
  40.                     }  
  41.                 } finally {  
  42.                     ......  
  43.                 }  
  44.             } catch (RemoteException ex) {  
  45.             }  
  46.             ......  
  47.         }  

去除了多余不需要关心的代码,主要的代码如上。根据前面setVisibility方法里boolean变量的值,能推断出几个关键分歧判断变量的值。

setVisibility(View.INVISIBLE)的场合:

    mVisible->ture   mViewVisibility->false    mRequestedVisible->false    visibleChanged->true    visible->false    于是reportSurfaceDestroyed执行,surfaceCreated不执行


setVisibility(View.VISIBLE)的场合:

    mVisible->false   mViewVisibility->true    mRequestedVisible->true    visibleChanged->true    visible->true    于是reportSurfaceDestroyed不执行,surfaceCreated执行


源码才是王道.......


上一篇:MySQL的sql_mode合理设置


下一篇:OleDb 内存泄露问题