Android WebView开发问题及优化汇总
我們?cè)趎ative與網(wǎng)頁相結(jié)合開發(fā)的過程中,難免會(huì)遇到關(guān)于WebView一些共通的問題。就我目前開發(fā)過程中遇到的問題以及最后得到的優(yōu)化方案都將在這里列舉出來。有些是老生常談,有些則是個(gè)人摸索得出解決方法。下面就是整理得到的些干貨。
1.加快HTML網(wǎng)頁裝載完成的速度
默認(rèn)情況html代碼下載到WebView后,webkit開始解析網(wǎng)頁各個(gè)節(jié)點(diǎn),發(fā)現(xiàn)有外部樣式文件或者外部腳本文件時(shí),會(huì)異步發(fā)起網(wǎng)絡(luò)請(qǐng)求下載文件,但如果在這之前也有解析到image節(jié)點(diǎn),那勢(shì)必也會(huì)發(fā)起網(wǎng)絡(luò)請(qǐng)求下載相應(yīng)的圖片。在網(wǎng)絡(luò)情況較差的情況下,過多的網(wǎng)絡(luò)請(qǐng)求就會(huì)造成帶寬緊張,影響到css或js文件加載完成的時(shí)間,造成頁面空白loading過久。解決的方法就是告訴WebView先不要自動(dòng)加載圖片,等頁面finish后再發(fā)起圖片加載。
故在WebView初始化時(shí)設(shè)置如下代碼:
| 1 2 3 4 5 6 7 | public void int () { if(Build.VERSION.SDK_INT >= 19) { webView.getSettings().setLoadsImagesAutomatically(true); } else { webView.getSettings().setLoadsImagesAutomatically(false); } } |
同時(shí)在WebView的WebViewClient實(shí)例中的onPageFinished()方法添加如下代碼:
| 1 2 3 4 5 6 | @Override public void onPageFinished(WebView view, String url) { if(!webView.getSettings().getLoadsImagesAutomatically()) { webView.getSettings().setLoadsImagesAutomatically(true); } } |
從上面的代碼,可以看出我們對(duì)系統(tǒng)API在19以上的版本作了兼容。因?yàn)?.4以上系統(tǒng)在onPageFinished時(shí)再恢復(fù)圖片加載時(shí),如果存在多張圖片引用的是相同的src時(shí),會(huì)只有一個(gè)image標(biāo)簽得到加載,因而對(duì)于這樣的系統(tǒng)我們就先直接加載。
2.自定義出錯(cuò)界面
當(dāng)WebView加載頁面出錯(cuò)時(shí)(一般為404 NOT FOUND),安卓WebView會(huì)默認(rèn)顯示一個(gè)賣萌的出錯(cuò)界面。但我們?cè)趺茨茏層脩舭l(fā)現(xiàn)原來我使用的是網(wǎng)頁應(yīng)用呢,我們期望的是用戶在網(wǎng)頁上得到是如原生般應(yīng)用的體驗(yàn),那就先要從干掉這個(gè)默認(rèn)出錯(cuò)頁面開始。當(dāng)WebView加載出錯(cuò)時(shí),我們會(huì)在WebViewClient實(shí)例中的onReceivedError()方法接收到錯(cuò)誤,我們就在這里做些手腳:
| 1 2 3 4 5 6 | @Override public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mErrorFrame.setVisibility(View.VISIBLE); } |
從上面可以看出,我們先使用loadDataWithBaseURL清除掉默認(rèn)錯(cuò)誤頁內(nèi)容,再讓我們自定義的View得到顯示(mErrorFrame為蒙在WebView之上的一個(gè)LinearLayout布局,默認(rèn)為View.GONE)。
3.是否存在滾動(dòng)條
當(dāng)我們做類似上拉加載下一頁這樣的功能的時(shí)候,頁面初始的時(shí)候需要知道當(dāng)前WebView是否存在縱向滾動(dòng)條,如果有則不加載下一頁,如果沒有則加載下一頁直到其出現(xiàn)縱向滾動(dòng)條。首先繼承WebView類,在子類添加下面的代碼:
| 1 2 3 | public boolean existVerticalScrollbar () { return computeVerticalScrollRange() > computeVerticalScrollExtent(); } |
computeVerticalScrollRange得到的是可滑動(dòng)的最大高度,computeVerticalScrollExtent得到的是滾動(dòng)把手自身的高,當(dāng)不存在滾動(dòng)條時(shí),兩者的值是相等的。當(dāng)有滾動(dòng)條時(shí)前者一定是大于后者的。
4.是否已滾動(dòng)到頁面底部
同樣我們?cè)谧錾侠虞d下一頁這樣的功能時(shí),也需要知道當(dāng)前頁面滾動(dòng)條所處的狀態(tài),如果快到底部,則要發(fā)起網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)更新網(wǎng)頁。同樣繼承WebView類,在子類覆蓋onScrollChanged方法,具體如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 | @Override protected void onScrollChanged(int newX, int newY, int oldX, int oldY) { super.onScrollChanged(newX, newY, oldX, oldY); if (newY != oldY) { float contentHeight = getContentHeight() * getScale(); // 當(dāng)前內(nèi)容高度下從未觸發(fā)過, 瀏覽器存在滾動(dòng)條且滑動(dòng)到將抵底部位置 if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) { // TODO Something... mCurrContentHeight = contentHeight; } } } |
上面mCurrContentHeight用于記錄上次觸發(fā)時(shí)的網(wǎng)頁高度,用來防止在網(wǎng)頁總高度未發(fā)生變化而目標(biāo)區(qū)域發(fā)生連續(xù)滾動(dòng)時(shí)會(huì)多次觸發(fā)TODO,mThreshold是一個(gè)閾值,當(dāng)頁面底部距離滾動(dòng)條底部的高度差<=這個(gè)值時(shí)會(huì)觸發(fā)TODO。
5.遠(yuǎn)程網(wǎng)頁需訪問本地資源
當(dāng)我們?cè)赪ebView中加載出從web服務(wù)器上拿取的內(nèi)容時(shí),是無法訪問本地資源的,如assets目錄下的圖片資源,因?yàn)檫@樣的行為屬于跨域行為(Cross-Domain),而WebView是禁止的。解決這個(gè)問題的方案是把html內(nèi)容先下載到本地,然后使用loadDataWithBaseURL加載html。這樣就可以在html中使用?file:///android_asset/xxx.png?的鏈接來引用包里面assets下的資源了。示例如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private void loadWithAccessLocal(final String htmlUrl) { new Thread(new Runnable() { public void run() { try { final String htmlStr = NetService.fetchHtml(htmlUrl); if (htmlStr != null) { TaskExecutor.runTaskOnUiThread(new Runnable() { @Override public void run() { loadDataWithBaseURL(htmlUrl, htmlStr, "text/html", "UTF-8", ""); } }); return; } } catch (Exception e) { Log.e("Exception:" + e.getMessage()); } TaskExecutor.runTaskOnUiThread(new Runnable() { @Override public void run() { onPageLoadedError(-1, "fetch html failed"); } }); } }).start(); } |
上面有幾點(diǎn)需要注意:
- 從網(wǎng)絡(luò)上下載html的過程應(yīng)放在工作線程中
- html下載成功后渲染出html的步驟應(yīng)放在UI主線程,不然WebView會(huì)報(bào)錯(cuò)
- html下載失敗則可以使用我們前面講述的方法來顯示自定義錯(cuò)誤界面
完整的demo項(xiàng)目代碼我已放到:http://yunpan.cn/cgQPvJQxxkCBj?(提取碼:6712)。
6.ViewPager里非首屏WebView點(diǎn)擊事件不響應(yīng)
如果你的多個(gè)WebView是放在ViewPager里一個(gè)個(gè)加載出來的,那么就會(huì)遇到這樣的問題。ViewPager首屏WebView的創(chuàng)建是在前臺(tái),點(diǎn)擊時(shí)沒有問題;而其他非首屏的WebView是在后臺(tái)創(chuàng)建,滑動(dòng)到它后點(diǎn)擊頁面會(huì)出現(xiàn)如下錯(cuò)誤日志:
20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found
解決這個(gè)問題的辦法是繼承WebView類,在子類覆蓋onTouchEvent方法,填入如下代碼:
| 1 2 3 4 5 6 7 | @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY()); } return super.onTouchEvent(ev); } |
該方法的最先提出在WebView in ViewPager not receive user inputs。
7.WebView硬件加速導(dǎo)致頁面渲染閃爍
4.0以上的系統(tǒng)我們開啟硬件加速后,WebView渲染頁面更加快速,拖動(dòng)也更加順滑。但有個(gè)副作用就是,當(dāng)WebView視圖被整體遮住一塊,然后突然恢復(fù)時(shí)(比如使用SlideMenu將WebView從側(cè)邊滑出來時(shí)),這個(gè)過渡期會(huì)出現(xiàn)白塊同時(shí)界面閃爍。解決這個(gè)問題的方法是在過渡期前將WebView的硬件加速臨時(shí)關(guān)閉,過渡期后再開啟,代碼如下:
| 1 2 3 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } |
8.避免addJavaScriptInterface帶來的安全問題
使用開源項(xiàng)目Safe Java-JS WebView Bridge可以很好替代addJavaScriptInterface方法,同時(shí)增加了異步回調(diào)等支持,并且不存在了安全風(fēng)險(xiǎn)。
9.WebView與上層父元素的TouchMove事件沖突
在開發(fā)過程中你可能會(huì)遇到這樣一種情況。端里面使用ViewPager嵌套了多個(gè)WebView頁面,同時(shí)某一個(gè)WebView中的頁面元素需要響應(yīng)TouchMove事件。詳細(xì)解決方案請(qǐng)移步:http://www.pedant.cn/2014/09/23/webview-touch-conflict
歡迎轉(zhuǎn)載,請(qǐng)注明出處鏈接!!!
來自:http://www.pedant.cn/2014/09/10/webview-optimize-points/
轉(zhuǎn)載于:https://www.cnblogs.com/AceIsSunshineRain/p/5198908.html
總結(jié)
以上是生活随笔為你收集整理的Android WebView开发问题及优化汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 来分期的购物额度1000可以用吗
- 下一篇: 花呗打电话过来是什么意思