Android WebView中那些不得不解決的坑~~

希爾瓦娜斯女神發表於2015-12-21

 

前面那張hybrid開發心得 有人問 怎麼解決不用onJsPrompt 來回撥js函式的問題。其實很簡單,就是在在你的jscalljava回撥函式內 另外開個執行緒去load js程式碼即可:

1 wb.post(new Runnable() {
2                 @Override
3                 public void run() {
4                     wb.loadUrl("javascript:display_alert()");
5                 }
6             });

 

好,然後開始說一下webview。webview其實我一直都很痛恨這個控制元件,你又不能不用,但是一旦大規模測試起來 你就發現這個webview真是坑。。。各種你想不到的錯誤 在各種奇怪的手機,各種不一樣的版本里

出現各種難以預料的問題。再加上monkey 時不時的 幫你跑點crush,烏雲平臺時不時給你爆點漏洞,感覺webview天生就是在考驗開發者的奇技淫巧。我自己也總結了下webview 下面的開發注意事項,現在總結出來,

希望能給你今後webview開發中 掃平一些障礙 提供一些幫助。

 

1.WebView的記憶體洩露。

關於這個問題,我很難給你一個清晰的描述,你在谷歌裡搜 webview lead memory 能搜到很多結果 甚至還有給谷歌提交的issue 哈哈,我也無法給出一個清晰的答案 在什麼時候 什麼版本那些手機上一定會出現記憶體洩露,

但是根據我自己的monkey結果來看,有時,webview記憶體洩露的情況還是很嚴重的,尤其是當你載入的頁面比較龐大的時候。解決方案 我查了很多也用了很多,但是都不太理想,最後看了下微信和qq的做法,試了一下是目前效果最好的,

就是 當你要用webview的時候,記得最好 另外單獨開一個程式 去使用webview 並且當這個 程式結束時,請手動呼叫System.exit(0)。

這是目前對於webview 記憶體洩露 最好的解決方案。使用此方法 所有因為webview引發的 資源無法釋放等問題 全部可以解決。

 

2.getSettings().setBuiltInZoomControls(true) 引發的crush。

這個方法呼叫以後 如果你觸控螢幕 彈出那個提示框還沒消失的時候 你如果activity結束了 就會報錯了。3.0以上 4.4以下很多手機會出現這種情況

所以為了規避他,我們通常是在activity的onDestroy方法裡手動的將webiew設定成 setVisibility(View.GONE)

 

3.onPageFinished 函式到底有用沒有?

多數開發者都是參考的http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android 這個上面的高票答案。

但其實根據我自己觀察,這個函式並沒有什麼卵用,有的時候是提前結束,有的時候就遲遲無法結束,你信這個函式 還不如信上帝,甚至於onProgressChanged這個函式

都比onPageFinished  要準一些。如果你的產品經理堅持你一定要實現這種功能的話,我建議你 提早結束他,否則卡在那使用者遲遲動不了 這種體驗不好。

有空的同學可以跟一下原始碼,onPageFinished  在不同的核心裡 呼叫的時機都不一樣。說實話 我也很醉。。。這個問題 有完美解決方案的 請知會我一下。。。

 

4.後臺無法釋放js 導致耗電。

這個可能很少有人知道,我也是被投訴過 才瞭解,在有的手機裡,你如果webview載入的html裡 有一些js 一直在執行比如動畫之類的東西,如果此刻webview 掛在了後臺

這些資源是不會被釋放 使用者也無法感知。。。導致一直佔有cpu 耗電特別快,所以大家記住了,如果遇到這種情況 請在onstop和onresume裡分別把setJavaScriptEnabled();

給設定成false和true。

 

5.如果實在不想用開額外程式的方式解決webview 記憶體洩露的問題,那麼下面的方法很大程度上可以避免這種情況

 1     public void releaseAllWebViewCallback() {
 2         if (android.os.Build.VERSION.SDK_INT < 16) {
 3             try {
 4                 Field field = WebView.class.getDeclaredField("mWebViewCore");
 5                 field = field.getType().getDeclaredField("mBrowserFrame");
 6                 field = field.getType().getDeclaredField("sConfigCallback");
 7                 field.setAccessible(true);
 8                 field.set(null, null);
 9             } catch (NoSuchFieldException e) {
10                 if (BuildConfig.DEBUG) {
11                     e.printStackTrace();
12                 }
13             } catch (IllegalAccessException e) {
14                 if (BuildConfig.DEBUG) {
15                     e.printStackTrace();
16                 }
17             }
18         } else {
19             try {
20                 Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback");
21                 if (sConfigCallback != null) {
22                     sConfigCallback.setAccessible(true);
23                     sConfigCallback.set(null, null);
24                 }
25             } catch (NoSuchFieldException e) {
26                 if (BuildConfig.DEBUG) {
27                     e.printStackTrace();
28                 }
29             } catch (ClassNotFoundException e) {
30                 if (BuildConfig.DEBUG) {
31                     e.printStackTrace();
32                 }
33             } catch (IllegalAccessException e) {
34                 if (BuildConfig.DEBUG) {
35                     e.printStackTrace();
36                 }
37             }
38         }
39     }

在webview的 destroy方法裡 呼叫這個方法就行了。

 

6.另外很多人 不知道webview 實際上有自己一套完整的cookie機制的,利用好這個 可以大大增加對客戶端的訪問速度。

實際上cookie就是存放在這個表裡的。

很多人都想要一個效果:網頁更新cookie 設定完cookie以後 不重新整理頁面即可生效。這個在2.3以下和2.3以上要實現的方法不太一樣,所以要做一次相容

 

 1   
 4     public void updateCookies(String url, String value) {
 5         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { // 2.3及以下
 6             CookieSyncManager.createInstance(getContext().getApplicationContext());
 7         }
 8         CookieManager cookieManager = CookieManager.getInstance();
 9         cookieManager.setAcceptCookie(true);
10         cookieManager.setCookie(url, value);
11         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
12             CookieSyncManager.getInstance().sync();
13         }
14     }

 

相關文章