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方法:

[java]  view plain copy print ?
  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方法:
[java]  view plain copy print ?
  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执行


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


相关文章
|
9月前
|
传感器 前端开发 Java
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
503 0
|
10月前
|
程序员 Android开发
Android 照相机 camera 操作封装
Android 照相机 camera 操作封装
|
Web App开发 编解码 安全
Android 12开发者预览版现已发布,包含众多亮点
Android 12开发者预览版现已发布,包含众多亮点
96 0
|
Android开发
Android 裁剪摄像头预览窗口-SurfaceView
Android 裁剪摄像头预览窗口-SurfaceView
541 0
Android 裁剪摄像头预览窗口-SurfaceView
|
小程序 IDE API
Android 端预览和调试小程序|学习笔记
快速学习 Android 端预览和调试小程序
114 0
Android 端预览和调试小程序|学习笔记
DHL
|
存储 算法 安全
Android 13这些权限废弃,你的应用受影响了吗?
在 Android 13 上废弃了文件访问权限,提供了一种选择媒体文件的工具,代替这些废弃的 API,而不需要授予对其整个媒体库的访问权限
DHL
607 0
Android 13这些权限废弃,你的应用受影响了吗?
|
XML 缓存 Android开发
Android Studio Dolphin | 2021.3.1不显示布局XML预览
Android Studio Dolphin | 2021.3.1不显示布局XML预览
1974 0
Android Studio Dolphin | 2021.3.1不显示布局XML预览
|
存储 XML 机器学习/深度学习
android CameraX牛刀小试-预览、抽帧、拍照功能实现
android CameraX牛刀小试-预览、抽帧、拍照功能实现
2266 0
android CameraX牛刀小试-预览、抽帧、拍照功能实现
|
移动开发 前端开发 JavaScript
真牛皮!Android-Camera内存问题剖析,满满干货指导
真牛皮!Android-Camera内存问题剖析,满满干货指导
|
API Android开发
Android中的拍照camera和camera2
在android我们可以调用系统的相机来进行照相,当然也可以设计自己的照相页面,通过surface进行预览,通过camera api来进行拍照即可。 在Android 5.0之后google推荐使用的Camera2 Api,但是由于兼容问题我们大部分还在使用Camera Api。这里我们一起简单介绍一下,仅仅是预览拍照,至于细节的设置,比如图像大小比例、对焦、图像旋转等就不一一细说了。 首先我们需要在布局中加入一个SurfaceView
639 0