UWP應(yīng)用,全稱或許可稱Windows通用平臺(tái)應(yīng)用,是微軟推出的新一代Windows應(yīng)用開發(fā)模型。但是自推出以來,卻飽受詬病,其中,易閃退是很多人對(duì)它的第一印象。今天,我們就來談一談UWP應(yīng)用閃退的問題,并教你如何解決它。
本文所述是立于開發(fā)者角度,即從應(yīng)用代碼解決問題。而非處于用戶角度,在應(yīng)用之外解決UWP應(yīng)用閃退的問題
大部分閃退的根源
UWP應(yīng)用不是瓷娃娃,沒那么易碎。“閃退”,歸根結(jié)蒂其實(shí)是Windows對(duì)系統(tǒng)的保護(hù),避免因應(yīng)用而干擾到系統(tǒng)運(yùn)行。這種處理方式是站在系統(tǒng)角度上的,但開發(fā)者和用戶都不領(lǐng)情。
用戶自不必說,應(yīng)用閃退,極大地影響用戶體驗(yàn),閃退了幾次就把軟件卸載了,閃退的應(yīng)用多了,連帶著對(duì)整個(gè)UWP應(yīng)用都討厭上了。
而開發(fā)者也很糾結(jié),用戶抱怨出現(xiàn)閃退,可在開發(fā)者這里沒辦法復(fù)現(xiàn),導(dǎo)致開發(fā)者調(diào)試?yán)щy,有時(shí)候也是不了了之。
那么大部分閃退的根源是什么呢?
一言以蔽之,就是出現(xiàn)了未捕獲的異常,即UnhandledException。
在寫應(yīng)用的時(shí)候,出現(xiàn)錯(cuò)誤的原因多種多樣,從大的架構(gòu)設(shè)計(jì)失當(dāng),到小的出現(xiàn)了不安全的空(Null)值。這些錯(cuò)誤,開發(fā)者有的可以在程序設(shè)計(jì)時(shí)就利用`try-catch`語句進(jìn)行捕獲,經(jīng)驗(yàn)越豐富的程序員,設(shè)計(jì)時(shí)考慮到的可能異常就越多。但是人力有時(shí)窮,不可能方方面面都考慮到,而程序一旦在運(yùn)行過程中出現(xiàn)了**未捕獲的異常**,應(yīng)用馬上閃退,毫無二話。
照這樣說,出現(xiàn)未捕獲的異常似乎是再所難免的,可為什么有些應(yīng)用基本不閃退呢?是它們的程序全身上下都是try-catch嗎?
肯定不是啦~
解決未捕獲的異常非常簡單,即便算上大括號(hào),也只需要5行代碼就可以搞定。
如何一勞永逸地解決閃退問題
如上節(jié)所述,絕大部分閃退的根源是未捕獲的異常。既然是未捕獲,那我們把它捕獲了不就完事了嗎?
說起來簡單,做起來……更簡單!
每一個(gè)新建的UWP應(yīng)用都有一個(gè)App.xaml的文件,其背后則有一個(gè)App.xaml.cs。
App.xaml.cs中包含著關(guān)于應(yīng)用啟動(dòng)、暫停等應(yīng)用層級(jí)的操作邏輯,這個(gè)我相信各位開發(fā)者都是知道的。而所有未捕獲的異常,最終都會(huì)冒泡到這里,所以這里是最后一關(guān)。換句話說,我們只要在這里設(shè)一道卡,抓住這個(gè)異常,不讓它觸發(fā)閃退機(jī)制就萬事大吉了。
App類派生自Application類,且自帶了一個(gè)事件,就是UnhandledException,說明是**當(dāng)異常可由應(yīng)用程序代碼處理,如從本機(jī)級(jí)別的Windows運(yùn)行時(shí)錯(cuò)誤轉(zhuǎn)發(fā)時(shí)發(fā)生。應(yīng)用程序可標(biāo)記事件數(shù)據(jù)中處理的匹配項(xiàng)**。
換句話說,人家早就想到會(huì)有閃退這種情況,已經(jīng)預(yù)先把這個(gè)事件給你定好了。那我們要做的就非常簡單了。
首先,在App的構(gòu)造函數(shù)里加上
this.UnhandledException +=OnUnhandledException;
給這個(gè)事件綁定上一個(gè)處理函數(shù)。
接下來,我們就來寫這個(gè)處理函數(shù):
private void OnUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
{
e.Handled=true;
}
就這樣,因出現(xiàn)未捕獲的異常而造成的閃退就解決了,這個(gè)原因的閃退占了總體的九成以上。可以說,接下來,只要你的應(yīng)用不作死,不故意寫點(diǎn)死循環(huán),不搞不安全的騷操作,基本上就不會(huì)再閃退了。
閃退問題的后續(xù)處理
出現(xiàn)閃退,意味著程序有錯(cuò)誤未捕獲。既然有錯(cuò)誤,那就要解決。單靠一個(gè)e.Hanled=true;……
這種粗暴的解決方式雖然能夠一次性解決閃退問題,但是治標(biāo)不治本(雖然用戶并不清楚,但實(shí)際使用體驗(yàn)卻有了不少的提升)。作為軟件的設(shè)計(jì)者,我們依然需要知道具體是哪里出現(xiàn)了問題,錯(cuò)誤的原因是什么,這就涉及到了異常的后續(xù)處理。
如果你做的應(yīng)用上架到了微軟應(yīng)用商店,那么在微軟應(yīng)用商店的后臺(tái),會(huì)記錄你的軟件在用戶處的使用狀況,而當(dāng)出現(xiàn)異常的時(shí)候,也會(huì)上傳到你的軟件后臺(tái),這樣就方便管理了:
你可以在后臺(tái)觀察出現(xiàn)的異常,然后在程序里解決它。
但是凡事總有例外,微軟應(yīng)用商店也不能捕獲所有的異常并加以分析,這里分享一個(gè)例子:
我在開發(fā)WFA的時(shí)候,遇到過一個(gè)棘手的問題,Win10 14393的用戶在打開應(yīng)用設(shè)置時(shí)應(yīng)用會(huì)閃退,而更高版本的則不會(huì)。當(dāng)時(shí)在應(yīng)用商店后臺(tái)查看時(shí),它也不知道原因,顯示一個(gè)Unkonwn Exception,這我就很尷尬了啊。
百思不得其解的情況下,我在App.xaml.cs的異常捕獲函數(shù)中加了個(gè)小東西,即捕獲到異常后,將異常的解釋傳到我的數(shù)據(jù)庫里。通過這樣的方式,我很快找到了問題的成因,即AutoSuggestBox控件的某個(gè)樣式在14393系統(tǒng)中不支持,這導(dǎo)致應(yīng)用無法渲染,直接閃退了。
雖然最后我還是放棄了14393的支持(使用了ContentDialog的新控件),但這種本地處理也可以作為一個(gè)經(jīng)驗(yàn)保留下來(現(xiàn)在的WFA也沒有在異常捕獲里加上傳代碼了)。
小小總結(jié)一下,閃退異常的后續(xù)處理可以通過兩種方式來解決:
? 一種是依賴微軟應(yīng)用商店的異常上傳機(jī)制,這種方式便于管理;
? 當(dāng)前種處理方式不能滿足需求時(shí),可以在App.xaml.cs中的異常捕獲函數(shù)里進(jìn)行本地處理,將更為詳細(xì)的信息上傳到你的數(shù)據(jù)庫中,便于你進(jìn)行分析。
不過要注意,由于發(fā)布的安裝包基本都是Release的,異常捕獲不會(huì)有Debug時(shí)那樣精準(zhǔn),有時(shí)候也需要自己根據(jù)情況進(jìn)行分析。
第二種閃退原因
閃退原因可分為兩部分,一種是我前面講的代碼中出現(xiàn)了未捕獲的異常,而另一種,則是應(yīng)用渲染無法獲取到對(duì)應(yīng)資源,這一點(diǎn)就尤其顯示出UWP開發(fā)平臺(tái)的不成熟性了。
這種原因說白了其實(shí)就是“樣式引起的閃退”,這個(gè)在我前面分享的WFA的例子中也提及過。
開發(fā)過UWP應(yīng)用的同學(xué)對(duì)于控件樣式應(yīng)該不陌生吧。這個(gè)是UI的關(guān)鍵部分。而控件樣式的設(shè)計(jì),低版本(15063及以下)可以使用Blend,而更高版本,Blend尚未支持,就需要自己創(chuàng)建控件樣式的副本,手動(dòng)對(duì)XAML代碼進(jìn)行修改(我現(xiàn)在已經(jīng)更偏向于這一種處理方式了)。
不論是利用Blend還是手動(dòng)改,都需要?jiǎng)?chuàng)建控件樣式的副本,這個(gè)副本依據(jù)什么創(chuàng)建的呢?依據(jù)的是系統(tǒng)默認(rèn)的樣式。而系統(tǒng)默認(rèn)的樣式有一個(gè)很嚴(yán)重的問題,以16299為例。
眾所周知,在16299中,Win10采用了Fluent Design,很多控件的默認(rèn)樣式都進(jìn)行了更新,添加了一種名為AcrylicBrush的筆刷,而在最新的17134中,則有Reveal光效。當(dāng)這些僅特定版本支持的特殊樣式被內(nèi)化到系統(tǒng)默認(rèn)樣式中,一件凄涼的事情就發(fā)生了:
一個(gè)最為基礎(chǔ)的控件,你認(rèn)為的各個(gè)版本都會(huì)支持的控件,卻偏偏成了閃退的罪魁禍?zhǔn)住?/p>
原因就在于你使用高版本W(wǎng)in10進(jìn)行開發(fā)時(shí),控件的默認(rèn)樣式已經(jīng)不再支持低版本了,而你卻對(duì)此并不了解,導(dǎo)致你沒修改控件的樣式。這樣的應(yīng)用做出來,雖然名義上支持低版本,但是低版本打開后會(huì)因?yàn)閼?yīng)用找不到對(duì)應(yīng)的系統(tǒng)資源而無法渲染,因此閃退。
因這種原因而閃退的應(yīng)用也屢見不鮮,很多時(shí)候都是開發(fā)者沒有經(jīng)過認(rèn)真比對(duì)而強(qiáng)行上新的效果造成的。
但是你說這個(gè)是開發(fā)者的原因嗎?或許是,但微軟也需要承擔(dān)一定的責(zé)任。你控件更新就更新吧,好歹告訴我一聲啊,就算沒寫什么更新說明,那么在創(chuàng)建默認(rèn)樣式時(shí),加個(gè)波浪線,告訴一聲“該樣式在當(dāng)前軟件的最低系統(tǒng)版本中不受支持”也好啊。但很可惜的是,目前這種提示文字有,但不全面,仍有一些樣式?jīng)]有被包括在提醒列表之內(nèi)。
所以,當(dāng)你在App.xaml.cs中完成了對(duì)代碼的異常捕獲后,如果應(yīng)用依然會(huì)出現(xiàn)閃退,那么你就要考慮一下這種樣式原因了。
個(gè)人博客地址:blog.richasy.cn
上周二的補(bǔ)丁日,微軟為Windows 10全部四個(gè)已經(jīng)發(fā)布的正式版推送了系統(tǒng)更新,帶來了多達(dá)48項(xiàng)安全修復(fù)。
今天中午,官方突然上線KB4034661補(bǔ)丁,面向年度更新用戶,使得版本號(hào)再次從Build 14393.1593升級(jí)為Build 14393.1613。
更新內(nèi)容方面,修復(fù)也達(dá)到了20項(xiàng)整,包括——
新加入d3dcompiler_47.dll動(dòng)態(tài)鏈接庫文件、修復(fù)UAC提示激活后被已打開程序遮擋、加密硬盤阻撓系統(tǒng)啟動(dòng)、三方磁盤清理工具導(dǎo)致啟動(dòng)項(xiàng)丟失等問題。
手動(dòng)打補(bǔ)丁戳這里