記一次bug修復 -運用Android的窗口管理機制

前幾天碧注,在編寫公司普通業(yè)務(wù)代碼的過程中嚣伐,遇到個bug,修復之后覺得還是挺有意思的萍丐,所以跟大家分享下哈~

為什么覺得這個bug比較有意思呢轩端?因為這個bug不是本人最常見的老臉孔nullPointer、outOfIndexBounds了逝变,解決這個bug要了解Android的窗口管理機制基茵,要是我之前沒系統(tǒng)地學習過,估計我肯定百思不得其解壳影。拱层。。不過掌握了相關(guān)的知識后宴咧,解決這個bug那是小菜一碟根灯。所以內(nèi)心不禁沾沾自喜,畢竟我努力學進階知識很大的一個動機就是為了從容面對bug啊@臃巍纳猪!對一個bug毫無頭緒甚至連errorMessage都讀不懂的羞愧感我真的怕了。桃笙。氏堤。

具體的Android的窗口管理機制就不在此講了。如果你了解主線程的消息循壞機制搏明,那會對本文理解得更加清晰哈~

背景是這樣的:
公司的APP的業(yè)務(wù)大多是很常見的信息展示鼠锈、響應(yīng)用戶操作事件。對于每一個網(wǎng)絡(luò)請求星著,都會在等待后臺返回時顯示個Loading動畫脚祟,表示正在處理中(很多APP也是這樣做的啦)。邏輯大概是這樣

showLoading();
//這里進行網(wǎng)絡(luò)請求
dismissLoading();  //接收到響應(yīng)時隱藏掉

這樣做一直以來都很和諧强饮。直到前幾天在寫一個業(yè)務(wù),是讓用戶可以上傳圖片的为黎。寫過上傳圖片業(yè)務(wù)的朋友都應(yīng)該比較熟悉邮丰,一般的公司處理上傳圖片都要經(jīng)過兩步:第一步獲取token,第二步才上傳到七牛铭乾。獲取token對用戶來說是感知不到的剪廉,在他們眼中上傳圖片就是一步到位,所以我們這兩個網(wǎng)絡(luò)請求是第一步緊接著第二步的炕檩。當我想都沒想就寫下以下邏輯代碼并測試時斗蒋,APP閃退了:

showLoading();
//這里獲取token
dismissLoading(); 
showLoading();
//這里上傳圖片到七牛
dismissLoading(); 

Logcat信息如下:


0C291BBF-C833-45F4-A8FE-4F15915AE0D9.png

(好吧還是老臉孔NullPointerException??)
日志顯示loading這個變量為空

因為APP里顯示的是統(tǒng)一的Loadind動畫,而這個Loading動畫是同事寫的笛质,我并不熟悉泉沾。于是點進去看看,首先是showLoading()和dismissLoading()兩個函數(shù)

protected void showLoading(){
    loading = Loading.newInstance();
    loading.show(getFragmentManager(),"loading");
}

protected void dismissLoading(){
    if (loading != null) {
        loading.dismiss();
    }
}

這兩個函數(shù)就是通過loading這個變量來控制Loading動畫的了妇押,再點進去這個loading跷究,看看是何方神圣

public class Loading extends BaseDialogFragment{
    private static Loading loading;

    public static Loading newInstance() {
        loading = new Loading();
        Bundle bundle = new Bundle();
        loading.setArguments(bundle);
        return loading;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = loading.getArguments();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        loading = null;
    }
}

可以看到,loading是個static變量敲霍,而且在每次showLoading()時俊马,loading會被賦予新變量 loading = new Loading(); 每次dismissLoading()時,loading變量會被設(shè)為空變量 loading = null;

然后debug一下肩杈,發(fā)覺奔潰是發(fā)生在第二次showLoading()的時候柴我,也就是第一步獲取token成功后,第二步上傳到七牛前的那個showLoading()扩然。
我覺得很奇怪艘儒,showLoading()方法中已經(jīng)確保了loading變量不為空 loading = Loading.newInstance(); 緊接著下一行代碼就是 loading.show(getFragmentManager(),"loading"); 了啊,為什么loading變量突然就變空了?彤悔?嘉抓?

927FD7C3-40D3-4450-81FC-822FA401CBD4.jpg

冷靜下來再看看代碼,看到Loading是繼承BaseDialogFragment的晕窑。條件反射般聯(lián)想到抑片,Dialog是一種窗口!杨赤!對于窗口的管理應(yīng)該注意3ㄕ!對于我們APP的主線程來說疾牲,這里的創(chuàng)建/銷毀一個Dialog其實是一個異步非阻塞任務(wù)V采印!

我們來分析一下:第一次dismissLoading()時其實只是通過binder告訴WMS阳柔,我要銷毀這個Dialog焰枢,征求WMS的允許和調(diào)度;然后我們的APP還沒來得及接收到WMS的反饋舌剂,緊接著就繼續(xù)執(zhí)行第二步的showLoading()了济锄,即告訴WMS,我要顯示這個Dialog霍转。但注意此時Dialog還沒有真的被銷毀再顯示荐绝,我們的APP只是向WMS發(fā)出了請求,因為這兩個過程都需要WMS的允許和配合避消。
當我們的APP的主線程收到WMS的返回的msg時低滩,消息隊列里必定是銷毀Dialog的msg在先,顯示Dialog的msg在后的岩喷。處理銷毀Dialog的msg時恕沫,我們會執(zhí)行onDestroyView()里的 loading = null ,loading變量賦值為null纱意;緊接著再處理顯示Dialog的msg昏兆,就會執(zhí)行onCreate()里的loading.getArguments();這時候當然報NullPointerException啦~~

所以妇穴,這個bug時由于我沒重視到窗口的創(chuàng)建/銷毀是個異步任務(wù)所造成的~要是不了解這個機制爬虱,估計我根本不會意識到這個問題,而會覺得創(chuàng)建/銷毀Dialog跟View.setVisiable(boolean)差不多呢腾它。跑筝。。這種情況瞒滴,估計加多少班都修復不了這個bug曲梗。赞警。。

既然弄清了問題出在哪虏两,那解決方法很簡單愧旦,第一步和第二步之間不要操作Loadind動畫就好了~

showLoading();
//這里獲取token
//dismissLoading(); 
//showLoading();
//這里上傳圖片到七牛
dismissLoading(); 

感悟:Android的窗口管理機制涉及的東西比較廣,他們之間的調(diào)用鏈定罢,類和方法的具體名字笤虫,我看了又忘??。不過整個機制我是理解并且大體掌握的祖凫,這些知識不進是進階必須琼蚯,而且還是修復某些bug所必須掌握的利器??解決這個bug比平時解決的那些OutOfIndexException要爽多了??


9F43C1EC-B4A2-456E-B154-012D1046C780.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惠况,隨后出現(xiàn)的幾起案子遭庶,更是在濱河造成了極大的恐慌,老刑警劉巖稠屠,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峦睡,死亡現(xiàn)場離奇詭異,居然都是意外死亡权埠,警方通過查閱死者的電腦和手機榨了,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弊知,“玉大人,你說我怎么就攤上這事粱快≈韧” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵事哭,是天一觀的道長漫雷。 經(jīng)常有香客問我,道長鳍咱,這世上最難降的妖魔是什么降盹? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮谤辜,結(jié)果婚禮上蓄坏,老公的妹妹穿的比我還像新娘。我一直安慰自己丑念,他們只是感情好涡戳,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脯倚,像睡著了一般渔彰。 火紅的嫁衣襯著肌膚如雪嵌屎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天恍涂,我揣著相機與錄音宝惰,去河邊找鬼。 笑死再沧,一個胖子當著我的面吹牛尼夺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播产园,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼汞斧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了什燕?” 一聲冷哼從身側(cè)響起粘勒,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屎即,沒想到半個月后庙睡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡技俐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年乘陪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雕擂。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡啡邑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出井赌,到底是詐尸還是另有隱情谤逼,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布仇穗,位于F島的核電站流部,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纹坐。R本人自食惡果不足惜枝冀,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耘子。 院中可真熱鬧果漾,春花似錦、人聲如沸谷誓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽片林。三九已至端盆,卻和暖如春怀骤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背焕妙。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工蒋伦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焚鹊。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓痕届,卻偏偏與公主長得像,于是被迫代替她去往敵國和親末患。 傳聞我的和親對象是個殘疾皇子研叫,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容