天天看點

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

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

源碼才是王道.......

繼續閱讀