遇到的問題:有GIF的動(dòng)態(tài)圖片和圖片較多的頁面會(huì)閃爍不停锨用,屋群、webView滑動(dòng)到底部部分文字也會(huì)閃爍
webVIew的功能請參考:https://blog.csdn.net/janice0529/article/details/41318755
造成閃爍的原因是WebView在Android5.0開始默認(rèn)開啟了硬件加速,從Android3.0(API Level 11)開始举瑰,支持硬件加速收壕,可充分利用GPU的特性,使得界面渲染更加平滑何陆,但是會(huì)消耗更多內(nèi)存RAM。但是硬件加速自身并非完美豹储,在某些Android5.0的rom上贷盲,由于內(nèi)存RAM分配的問題,如果代碼不當(dāng)剥扣,會(huì)引發(fā)閃屏巩剖、花屏等渲染問題
硬件加速的好處
硬件加速對(duì)渲染的流暢度有大幅提升。
在開啟硬件加速后钠怯,上下拖動(dòng)列表的感覺是沒有跳幀的平滑拖動(dòng)感佳魔,如果沒有硬件加速,拖動(dòng)時(shí)能感受到有丟幀呻疹。
在窗體切換動(dòng)畫上也類似吃引,硬件加速開關(guān)對(duì)切換動(dòng)畫的影響很大。
對(duì)于video刽锤、canvas镊尺、webgl,沒有硬件加速是沒法商用的并思,Android webview里video標(biāo)簽里的視頻如果沒有硬件加速會(huì)看不到畫面庐氮。
硬件加速的代價(jià)
硬件加速屬于雙緩沖機(jī)制,使用顯存進(jìn)行頁面渲染(使用較少的物理內(nèi)存)宋彼,導(dǎo)致更頻繁的顯存操作弄砍,可能引起以下現(xiàn)象:
白屏、花屏输涕、閃屏音婶;
低RAM內(nèi)存配置手機(jī)上閃退。
雖然新出的Android5.0的手機(jī)整體配置較高(顯存較大)莱坎,但是如果頁面中使用大量圖片或者過于復(fù)雜的CSS樣式時(shí)同樣容易出現(xiàn)白屏衣式、花屏、閃屏現(xiàn)象檐什。
解決硬件加速造成的問題有2個(gè)思路碴卧,1.降低頁面的內(nèi)存占用,給硬件加速騰出RAM乃正;2.在適當(dāng)?shù)牡胤疥P(guān)閉硬件加速住册。
方案1:通過其他方式降低頁面的內(nèi)存占用,給硬件加速騰出RAM
App中占用RAM比較多的地方包括同時(shí)顯示的webview的數(shù)量和webview的dom體積以及圖片體積瓮具。
大多數(shù)開發(fā)者報(bào)App閃屏荧飞,一問下來大多數(shù)是開啟硬件加速且這3塊的代碼有問題凡人。
努力優(yōu)化這3塊就能解決問題。
我們遇到有開發(fā)者的App一個(gè)界面并顯3個(gè)webview叹阔,其中一個(gè)webview里顯示幾十張?bào)w積數(shù)M的圖划栓,這樣的App渲染必然異常。
- 圖片處理
圖片是已知問題中最高概率發(fā)生的問題条获,也是解決起來最簡單有效的問題忠荞。
把圖片裁剪到幾十K,即便還是3個(gè)webview也不再出問題帅掘。
有些app里設(shè)了很大的背景圖委煤,此時(shí)非常影響渲染,請盡量不要設(shè)背景圖或使用少量的背景圖修档。
如果要顯示清晰高清圖碧绞,盡量設(shè)計(jì)成不在同一界面并顯多張高清大圖。
- webview處理
關(guān)于webview的并顯數(shù)量吱窝,常見的并顯結(jié)構(gòu)有解決列表滾動(dòng)的父子窗體讥邻、側(cè)滑菜單webview、底部選項(xiàng)卡webview院峡。
其中底部選項(xiàng)卡webview最占內(nèi)存兴使,如果必須使用這種設(shè)計(jì),就更要注意圖片體積的控制照激。
webview側(cè)滑菜單其實(shí)可以盡量改為div方式的側(cè)滑菜單发魄。
webview側(cè)滑菜單比div側(cè)滑菜單的優(yōu)勢是菜單rom復(fù)雜也可以平滑移動(dòng),以及可以蓋住native的控件比如plus.map俩垃,但我們?nèi)匀唤ㄗh非必要不使用webview側(cè)滑菜單励幼,把側(cè)滑菜單設(shè)計(jì)的簡單點(diǎn),采用div方式會(huì)更節(jié)約內(nèi)存口柳。
解決列表流暢滾動(dòng)的父子窗體苹粟,制作時(shí)注意把子窗體dock,dock模式能降低渲染壓力跃闹,減少并顯的webview的顯示區(qū)域嵌削。
- HTML、JS辣卒、CSS代碼處理
減少dom復(fù)雜度掷贾,很多開發(fā)者的代碼里div反復(fù)單層嵌套睛榄,毫無意義并且增加dom解析和渲染的壓力荣茫;
減少重型js框架的依賴,angular场靴、jq能不用就不用啡莉;
減少css代碼港准,盡可能的少寫css,不要寫互相覆蓋的無效css咧欣,不要使用復(fù)雜的css計(jì)算模型浅缸;
css里少用百分比方式的定位和寬高計(jì)算,少用padding魄咕、margin衩椒。有的開發(fā)者的界面元素剛顯示時(shí)在這個(gè)位置,過一會(huì)兒抖動(dòng)一下往下移動(dòng)了幾個(gè)像素哮兰,就是因?yàn)閙argin毛萌、padding生效晚導(dǎo)致二次渲染。
如果有圖片輪播喝滞,且發(fā)生閃屏阁将,把自動(dòng)輪播禁用掉,不要自動(dòng)切換圖片右遭。
- webview動(dòng)畫切換改為pop-in
pop-in動(dòng)畫的切換是有自動(dòng)截圖處理的做盅,這種動(dòng)畫發(fā)生花屏閃屏的概率要比較低。
- webview的出入椌焦控制
為了節(jié)省內(nèi)存吹榴,不顯示的webview默認(rèn)是出棧的。
在返回時(shí)滚婉,之前的窗體會(huì)重新入棧腊尚,有時(shí)這種重新入棧渲染的過程也會(huì)發(fā)生白屏。
如果你的app內(nèi)存占用不高满哪,可以控制一些界面不出棧婿斥,返回時(shí)就會(huì)直接看到之前的內(nèi)容。
控制不出棧的api在http://www.html5plus.org/doc/zh_cn/webview.html哨鸭,這里搜render來控制民宿。
方案2
造成閃爍的原因是WebView5.0開啟了硬件加速,所以首要任務(wù)是關(guān)閉硬件加速像鸡,有三種
1活鹰、 AndroidManifest.xml中的Activity配置:android:hardwareAccelerated="false"
2、WebView xml中:android:layerType="software"只估,ListView(或者外層嵌套ScrollView)android:layerType="software”
3志群、Java代碼設(shè)置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
但是關(guān)閉硬件加速后會(huì)造成:View too large to fit into drawing cache, needs 183047040 bytes, only 8294400 available。有人說是設(shè)置android:hardwareAccelerated="false"即可解決蛔钙,但本人項(xiàng)目中并無卵用锌云,所以,
1吁脱、設(shè)置:mWebView.setDrawingCacheEnabled(false); mWebView.getSettings().setLoadWithOverviewMode(true);
2重寫webView
public class MyWebView extends android.webkit.WebView {
public MyWebView(Context context) {
super(context);
}
public MyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
invalidate();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
mWebView.setDrawingCacheEnabled(false);
mWebView.getSettings().setLoadWithOverviewMode(true);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl(url);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
handler.proceed();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mWebView.loadUrl(url);
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
});
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
});