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
plaincopyprint?
- @Override
- public void setVisibility(int visibility) {
- super.setVisibility(visibility);
- mViewVisibility = visibility == VISIBLE;
- mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow(false, false);
- }
这里设置几个全局boolean变量,例如调用setVisibility(View.INVISIBLE)的时候,mViewVisibility和mRequestedVisible都被赋为false,然后调用updateWindow方法:
[java] view
plaincopyprint?
- private void updateWindow(boolean force, boolean redrawNeeded) {
- ......
- final boolean visibleChanged = mVisible != mRequestedVisible
- || mNewSurfaceNeeded;
- final boolean typeChanged = mType != mRequestedType;
- if (force || creating || formatChanged || sizeChanged || visibleChanged
- || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
- || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
- ......
- try {
- final boolean visible = mVisible = mRequestedVisible;
- ......
- if (visibleChanged && (!visible || mNewSurfaceNeeded)) {
- reportSurfaceDestroyed();
- }
- ......
- try {
- ......
- if (visible) {
- mDestroyReportNeeded = true;
- if (visibleChanged) {
- mIsCreating = true;
- for (SurfaceHolder.Callback c : callbacks) {
- c.surfaceCreated(mSurfaceHolder);
- }
- }
- } else {
- ......
- }
- } finally {
- ......
- }
- } catch (RemoteException ex) {
- }
- ......
- }
去除了多余不需要关心的代码,主要的代码如上。根据前面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执行
源码才是王道.......