webview api介紹+解決記憶體洩漏+js互動
1:建立webview
一般建立webview不採用在layout中直接去定義,而是用程式碼new一個webview出來,並且用RelativeLayout或LinearLayout做一個佔位.
<LinearLayout android:id="@+id/wv_robot" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
mLayout = (LinearLayout) findViewById(R.id.wv_robot); mWv = new WebView(getApplicationContext()); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mWv.setLayoutParams(params); mLayout.addView(mWv);
2:載入方式
//載入一個網頁: mWv.loadUrl("http://www.google.com/"); //載入apk包中的一個html頁面 mWv.loadUrl("file:///android_asset/receptionmode.html"); //載入手機本地的一個html頁面的方法: mWv.loadUrl("content://com.Android.htmlfileprovider/sdcard/test.html");
其中,載入本地時(第二種),把html檔案放置在asste資料夾中
3:API介紹
WebSettings webSettings = mWv.getSettings(); //支援js互動,這句程式碼必須加上,如果不加上,會造成圖片不能顯示,並且無法與js進行互動 webSettings.setJavaScriptEnabled(true);
//自適應螢幕 webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true);
//支援手勢進行放大縮小 webSettings.setBuiltInZoomControls(true); webSettings.setSupportZoom(true);
//隱藏放大鏡圖示 webSettings.setDisplayZoomControls(false);
//監聽載入進度 mWv.setWebChromeClient(new WebChromeClient(){ @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); } }); //監聽載入完成,開始===>設定WebViewClient就不會跳到我們的內建瀏覽器 mWv.setWebViewClient(new WebViewClient(){ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } });
//獲取當前的url mWv.getUrl();
//當用戶在當前webview中點選了按鈕,跳到下一個webview頁面,這時如果按物理返回鍵,是會銷燬當前的activty的,那我們想 //返回上一個webview頁面應該怎麼辦呢,加下面程式碼即可! @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (mWv.canGoBack()) {//判斷能不能後退 mWv.goBack(); return true; } } return super.onKeyDown(keyCode, event); }
mWv.setWebChromeClient(new WebChromeClient(){ //返回當前頁面的標題 @Override public void onReceivedTitle(WebView view, String title) { RobotActivity.this.setTitle(title); super.onReceivedTitle(view, title); } });
//回退的時候標題沒有換回來,這時再做一下操作即可 mWv.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // TODO Auto-generated method stub view.loadUrl(url); return false; } @Override public void onPageFinished(WebView view, String url) { setTitle(view.getTitle()); super.onPageFinished(view, url); } });
3:解決記憶體洩漏
載入一個Web頁面一般需要用到100M左右,而如果我們不及時清理WebView的記憶體,那最後可能會隨著記憶體消耗的不斷增加而發生OOM(Out
Of Memory)導致程式崩潰;
第一:
建立webview時,用Application的Context而不是用Activity的,理由同網上一致的說法,這樣能夠避免記憶體洩漏;同時網上也說如果用Application的Context的話,在有些時候會出錯,原因是Application到Activity型別轉換錯誤;但是這種說法並非正確的,所以這裡還是用Application的Context;
因為經過我的實際測試,在反覆New和銷燬WebView時,採用Application要比採用Activity的context要穩定地少用20~30M左右的記憶體,雖然
他們的記憶體都維持在一個穩定的消耗水平,但總體看來,Application要比Activity少那麼一點;
第二:
開啟另一個程序去開啟這個activity,避免記憶體洩漏
<activity android:name=".iwith_control.ui.activity.RobotActivity" android:process=":xxx.xxx.process.web"> <intent-filter> <action android:name="com.xxx.xxx.robotactivity"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
一般情況下,同一個應用程式的Activity元件都是執行在同一個程序中,但是,如果Activity配置了android:process這個屬性,那麼,它就會執行在自己
的程序中。如果android:process屬性的值以":"開頭,則表示這個程序是私有的;如果android:process屬性的值以小寫字母開頭,則表示這是一個全域性
程序,允許其它應用程式元件也在這個程序中執行。因此,這裡我們以":"開頭,表示建立的是私有的程序。事實上,這裡我們不要前面的":"也是可以
的,但是必須保證這個屬性性字串內至少有一個"."字元
跳轉:
Intent robotIntent = new Intent("com.xxx.xxx.robotactivity"); Bundle bbb = new Bundle(); bbb.putString("url", "哈哈"); robotIntent.putExtras(bbb); startActivity(robotIntent);接收:
String url = getIntent().getExtras().getString("url"); LogUtil.d("資料="+url);
第三:
回收記憶體
第一種做法:
@Override protected void onDestroy() { super.onDestroy(); clearWebViewResource(); }
/** * Description: release the memory of web view, otherwise it's resource will not be recycle. * Created by Michael Lee on 7/18/16 20:38 */ public void clearWebViewResource() { if (mWv != null) { mWv.removeAllViews(); // in android 5.1(sdk:21) we should invoke this to avoid memory leak // see (https://coolpers.github.io/webview/memory/leak/2015/07/16/ // android-5.1-webview-memory-leak.html) ((ViewGroup) mWv.getParent()).removeView(mWv); mWv.setTag(null); mWv.clearHistory(); mWv.destroy(); mWv = null; } }
第二種做法,直接殺掉當前程序(當橫屏切換到豎屏時,會直接返回到上一個頁面)
@Override protected void onDestroy() { super.onDestroy(); System.exit(0); }
還有一個問題要說的,也是在WebView使用的時候出現的問題:WebView中包含一個ZoomButtonsController,當使用web.getSettings().setBuiltInZoomControls(true);啟用該設定後,使用者一旦觸控式螢幕幕,就會出現縮放控制圖示。這個圖示過上幾秒會自動消失,但在3.0系統以上上,如果圖示自動消失前退出當前Activity的話,就會發生ZoomButton找不到依附的Window而造成程式崩潰,解決辦法很簡單就是在Activity的ondestory方法中呼叫web.setVisibility(View.GONE);方法,手動將其隱藏,就不會崩潰了。在3.0一下系統上不會出現該崩潰問題,真是各種崩潰,防不勝防啊!
最後還有記憶體洩漏的一些個建議:
In summary, to avoid context-related memory leaks, remember the following:
- Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
- Try using the context-application instead of a context-activity
- Avoid non-static inner classes in an activity if you don’t control their life cycle, use a static inner class and make a weak reference to the activity inside
And remember that a garbage collector is not an insurance against memory leaks. Last but not least, we try to make such leaks harder to make happen whenever we can.
js互動請看: