Android WebView開發問題及最佳化匯總

來源:互聯網
上載者:User

標籤:

我們在native與網頁相結合開發的過程中,難免會遇到關於WebView一些共通的問題。就我目前開發過程中遇到的問題以及最後得到的最佳化方案都將在這裡列舉出來。有些是老生常談,有些則是個人摸索得出解決方案。下面就是整理得到的些乾貨。

1.加快HTML網頁裝載完成的速度

預設情況html代碼下載到WebView後,webkit開始解析網頁各個節點,發現有外部樣式檔案或者外部指令檔時,會非同步發起網路請求下載檔案,但如果在這之前也有解析到image節點,那勢必也會發起網路請求下載相應的圖片。在網路情況較差的情況下,過多的網路請求就會造成頻寬緊張,影響到css或js檔案載入完成的時間,造成頁面空白loading過久。解決的方法就是告訴WebView先不要自動載入圖片,等頁面finish後再發起圖片載入。

故在WebView初始化時設定如下代碼:

1234567 public void int () {if(Build.VERSION.SDK_INT >= 19) {webView.getSettings().setLoadsImagesAutomatically(true);} else {webView.getSettings().setLoadsImagesAutomatically(false);}}

同時在WebView的WebViewClient執行個體中的onPageFinished()方法添加如下代碼:

123456 @Overridepublic void onPageFinished(WebView view, String url) {if(!webView.getSettings().getLoadsImagesAutomatically()) {webView.getSettings().setLoadsImagesAutomatically(true);}}

從上面的代碼,可以看出我們對系統API在19以上的版本作了相容。因為4.4以上系統在onPageFinished時再恢複圖片載入時,如果存在多張圖片引用的是相同的src時,會只有一個image標籤得到載入,因而對於這樣的系統我們就先直接載入。

2.自訂出錯介面

當WebView載入頁面出錯時(一般為404 NOT FOUND),安卓WebView會預設顯示一個賣萌的出錯介面。但我們怎麼能讓使用者發現原來我使用的是網頁應用呢,我們期望的是使用者在網頁上得到是如原生般應用的體驗,那就先要從幹掉這個預設出錯頁面開始。當WebView載入出錯時,我們會在WebViewClient執行個體中的onReceivedError()方法接收到錯誤,我們就在這裡做些手腳:

123456 @Overridepublic 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清除掉預設錯誤頁內容,再讓我們自訂的View得到顯示(mErrorFrame為蒙在WebView之上的一個LinearLayout布局,預設為View.GONE)。

3.是否存在捲軸

當我們做類似上拉載入下一頁這樣的功能的時候,頁面初始的時候需要知道當前WebView是否存在縱向捲軸,如果有則不載入下一頁,如果沒有則載入下一頁直到其出現縱向捲軸。首先繼承WebView類,在子類添加下面的代碼:

123 public boolean existVerticalScrollbar () {return computeVerticalScrollRange() > computeVerticalScrollExtent();}

computeVerticalScrollRange得到的是可滑動的最大高度,computeVerticalScrollExtent得到的是滾動把手自身的高,當不存在捲軸時,兩者的值是相等的。當有捲軸時前者一定是大於後者的。

4.是否已滾動到頁面底部

同樣我們在做上拉載入下一頁這樣的功能時,也需要知道當前頁面捲軸所處的狀態,如果快到底部,則要發起網路請求資料更新網頁。同樣繼承WebView類,在子類覆蓋onScrollChanged方法,具體如下:

123456789101112 @Overrideprotected void onScrollChanged(int newX, int newY, int oldX, int oldY) {super.onScrollChanged(newX, newY, oldX, oldY);if (newY != oldY) {float contentHeight = getContentHeight() * getScale();// 當前內容高度下從未觸發過, 瀏覽器存在捲軸且滑動到將抵底部位置if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) {// TODO Something...mCurrContentHeight = contentHeight;}}}

上面mCurrContentHeight用於記錄上次觸發時的網頁高度,用來防止在網頁總高度未發生變化而目的地區域發生連續滾動時會多次觸發TODO,mThreshold是一個閾值,當頁面底部距離捲軸底部的高度差<=這個值時會觸發TODO。

5.遠程網頁需訪問本地資源

當我們在WebView中載入出從web伺服器上拿取的內容時,是無法訪問本地資源的,如assets目錄下的圖片資源,因為這樣的行為屬於跨域行為(Cross-Domain),而WebView是禁止的。解決這個問題的方案是把html內容先下載到本地,然後使用loadDataWithBaseURL載入html。這樣就可以在html中使用 file:///android_asset/xxx.png 的連結來引用包裡面assets下的資源了。樣本如下:

123456789101112131415161718192021222324252627 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() {@Overridepublic void run() {loadDataWithBaseURL(htmlUrl, htmlStr, "text/html", "UTF-8", "");}});return;}} catch (Exception e) {Log.e("Exception:" + e.getMessage());} TaskExecutor.runTaskOnUiThread(new Runnable() {@Overridepublic void run() {onPageLoadedError(-1, "fetch html failed");}});}}).start();}

上面有幾點需要注意:

  • 從網路上下載html的過程應放在背景工作執行緒中
  • html下載成功後渲染出html的步驟應放在UI主線程,不然WebView會報錯
  • html下載失敗則可以使用我們前面講述的方法來顯示自訂錯誤介面

    完整的demo項目代碼我已放到:http://yunpan.cn/cgQPvJQxxkCBj (提取碼:6712)。
6.ViewPager裡非首屏WebView點擊事件不響應

如果你的多個WebView是放在ViewPager裡一個個載入出來的,那麼就會遇到這樣的問題。ViewPager首屏WebView的建立是在前台,點擊時沒有問題;而其他非首屏的WebView是在後台建立,滑動到它後點擊頁面會出現如下錯誤記錄檔:


20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found

解決這個問題的辦法是繼承WebView類,在子類覆蓋onTouchEvent方法,填入如下代碼:

1234567 @Overridepublic 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硬體加速導致頁面渲染閃爍

4.0以上的系統我們開啟硬體加速後,WebView渲染頁面更加快速,拖動也更加順滑。但有個副作用就是,當WebView視圖被整體遮住一塊,然後突然恢複時(比如使用SlideMenu將WebView從側邊滑出來時),這個過渡期會出現白塊同時介面閃爍。解決這個問題的方法是在過渡期前將WebView的硬體加速臨時關閉,過渡期後再開啟,代碼如下:

123 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);}
8.避免addJavaScriptInterface帶來的安全問題

使用開源項目Safe Java-JS WebView Bridge可以很好替代addJavaScriptInterface方法,同時增加了非同步回調等支援,並且不存在了安全風險。

9.WebView與上層父元素的TouchMove事件衝突

在開發過程中你可能會遇到這樣一種情況。端裡面使用ViewPager嵌套了多個WebView頁面,同時某一個WebView中的頁面元素需要響應TouchMove事件。詳細解決方案請移步:http://www.pedant.cn/2014/09/23/webview-touch-conflict

歡迎轉載,請註明出處連結!!!

來自:http://www.pedant.cn/2014/09/10/webview-optimize-points/

Android WebView開發問題及最佳化匯總

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.