前面那張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 }