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方法:
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執行
源碼才是王道.......