webview 閃爍

遇到的問題:有GIF的動態(tài)圖片和圖片較多的頁面會閃爍不停,、webView滑動到底部部分文字也會閃爍

webVIew的功能請參考:https://blog.csdn.net/janice0529/article/details/41318755

造成閃爍的原因是WebView在Android5.0開始默認(rèn)開啟了硬件加速,從Android3.0(API Level 11)開始,支持硬件加速,可充分利用GPU的特性,使得界面渲染更加平滑,但是會消耗更多內(nèi)存RAM。但是硬件加速自身并非完美,在某些Android5.0的rom上,由于內(nèi)存RAM分配的問題,如果代碼不當(dāng),會引發(fā)閃屏、花屏等渲染問題

硬件加速的好處

硬件加速對渲染的流暢度有大幅提升。
在開啟硬件加速后,上下拖動列表的感覺是沒有跳幀的平滑拖動感,如果沒有硬件加速,拖動時能感受到有丟幀。
在窗體切換動畫上也類似,硬件加速開關(guān)對切換動畫的影響很大。
對于video、canvas、webgl,沒有硬件加速是沒法商用的,Android webview里video標(biāo)簽里的視頻如果沒有硬件加速會看不到畫面。

硬件加速的代價

硬件加速屬于雙緩沖機(jī)制,使用顯存進(jìn)行頁面渲染(使用較少的物理內(nèi)存),導(dǎo)致更頻繁的顯存操作,可能引起以下現(xiàn)象:
白屏、花屏、閃屏;
低RAM內(nèi)存配置手機(jī)上閃退。
雖然新出的Android5.0的手機(jī)整體配置較高(顯存較大),但是如果頁面中使用大量圖片或者過于復(fù)雜的CSS樣式時同樣容易出現(xiàn)白屏、花屏、閃屏現(xiàn)象。
解決硬件加速造成的問題有2個思路,1.降低頁面的內(nèi)存占用,給硬件加速騰出RAM;2.在適當(dāng)?shù)牡胤疥P(guān)閉硬件加速。

方案1:通過其他方式降低頁面的內(nèi)存占用,給硬件加速騰出RAM

App中占用RAM比較多的地方包括同時顯示的webview的數(shù)量和webview的dom體積以及圖片體積。
大多數(shù)開發(fā)者報App閃屏,一問下來大多數(shù)是開啟硬件加速且這3塊的代碼有問題。
努力優(yōu)化這3塊就能解決問題。
我們遇到有開發(fā)者的App一個界面并顯3個webview,其中一個webview里顯示幾十張體積數(shù)M的圖,這樣的App渲染必然異常。

  • 圖片處理

圖片是已知問題中最高概率發(fā)生的問題,也是解決起來最簡單有效的問題。
把圖片裁剪到幾十K,即便還是3個webview也不再出問題。
有些app里設(shè)了很大的背景圖,此時非常影響渲染,請盡量不要設(shè)背景圖或使用少量的背景圖。
如果要顯示清晰高清圖,盡量設(shè)計成不在同一界面并顯多張高清大圖。

  • webview處理

關(guān)于webview的并顯數(shù)量,常見的并顯結(jié)構(gòu)有解決列表滾動的父子窗體、側(cè)滑菜單webview、底部選項(xiàng)卡webview。
其中底部選項(xiàng)卡webview最占內(nèi)存,如果必須使用這種設(shè)計,就更要注意圖片體積的控制。
webview側(cè)滑菜單其實(shí)可以盡量改為div方式的側(cè)滑菜單。
webview側(cè)滑菜單比div側(cè)滑菜單的優(yōu)勢是菜單rom復(fù)雜也可以平滑移動,以及可以蓋住native的控件比如plus.map,但我們?nèi)匀唤ㄗh非必要不使用webview側(cè)滑菜單,把側(cè)滑菜單設(shè)計的簡單點(diǎn),采用div方式會更節(jié)約內(nèi)存。
解決列表流暢滾動的父子窗體,制作時注意把子窗體dock,dock模式能降低渲染壓力,減少并顯的webview的顯示區(qū)域。

  • HTML、JS、CSS代碼處理

減少dom復(fù)雜度,很多開發(fā)者的代碼里div反復(fù)單層嵌套,毫無意義并且增加dom解析和渲染的壓力;
減少重型js框架的依賴,angular、jq能不用就不用;
減少css代碼,盡可能的少寫css,不要寫互相覆蓋的無效css,不要使用復(fù)雜的css計算模型;
css里少用百分比方式的定位和寬高計算,少用padding、margin。有的開發(fā)者的界面元素剛顯示時在這個位置,過一會兒抖動一下往下移動了幾個像素,就是因?yàn)閙argin、padding生效晚導(dǎo)致二次渲染。
如果有圖片輪播,且發(fā)生閃屏,把自動輪播禁用掉,不要自動切換圖片。

  • webview動畫切換改為pop-in

pop-in動畫的切換是有自動截圖處理的,這種動畫發(fā)生花屏閃屏的概率要比較低。

  • webview的出入??刂?/li>

為了節(jié)省內(nèi)存,不顯示的webview默認(rèn)是出棧的。
在返回時,之前的窗體會重新入棧,有時這種重新入棧渲染的過程也會發(fā)生白屏。
如果你的app內(nèi)存占用不高,可以控制一些界面不出棧,返回時就會直接看到之前的內(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)閉硬件加速后會造成: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);
          }
      });

目前我的情況和做法是:scrollView里嵌套了webVIew和listview。我直接把scrollview 的硬件加速關(guān)了就不閃爍了??墒腔瑒拥臅r候就沒那么順暢了(就是只在scrollView加上android:layerType="software")。本來是按照上面的辦法做的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容