WebView在現在的項目中使用的頻率應該還是非常高的。
- WebSettings
WebSettings webSettings = mWebView.getSettings();
webview.requestFocusFromTouch();//支持獲取手勢焦點,輸入用戶名、密碼或其他
setJavaScriptEnabled(true);//支持js
setPluginsEnabled(true);//支持插件 webSettings.setRenderPriority(RenderPriority.HIGH);//提高渲染的優先級設置自適應屏幕,兩者合用
setUseWideViewPort(true);//將圖片調整到適合webview的大小
setLoadWithOverviewMode(true);// 縮放至屏幕的大小setSupportZoom(true);//支持縮放,默認為true。是下面那個的前提。setBuiltInZoomControls(true);//設置內置的縮放控件。//若上面是false,則該WebView不可縮放,這個不管設置什么都不能縮放。setDisplayZoomControls(false);//隱藏原生的縮放控件setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);//支持內容重新布局 supportMultipleWindows();//多窗口 setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//關閉webview中緩存 setAllowFileAccess(true);//設置可以訪問文件 setNeedInitialFocus(true);//當webview調用requestFocus時為webview設置節點setJavaScriptCanOpenWindowsAutomatically(true);//支持通過JS打開新窗口 setLoadsImagesAutomatically(true);//支持自動加載圖片setDefaultTextEncodingName("utf-8");//設置編碼格式
關于緩存
緩存模式
LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據
LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。
LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據.
LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。
結合使用(離線加載):
if (NetStatusUtil.isConnected(getApplicationContext())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
//根據cache-control決定是否從網絡上取數據。
}else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//沒網,則從本地獲取,即離線加載
}
webSettings.setDomStorageEnabled(true);// 開啟 DOM storage API 功能webSettings.setDatabaseEnabled(true);//開啟 database storage API 功能
webSettings.setAppCacheEnabled(true);//開啟 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath);//設置 Application Caches 緩存目錄
**注意:**每個 Application 只調用一次 WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()
加載方式
**加載一個網頁:**
webView.loadUrl("[http://www.google.com/](http://www.google.com/)");
**加載apk包中的一個html頁面**
webView.loadUrl("file:///android_asset/test.html");
**加載手機本地的一個html頁面的方法:**
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
WebViewClient
**WebViewClient就是幫助WebView處理各種通知、請求事件的。**
打開網頁時不調用系統瀏覽器, 而是在本WebView中顯示:
mWebView.setWebViewClient(new WebViewClient(){
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);returntrue;
}
});
\
WebViewClient方法
WebViewClient mWebViewClient =new WebViewClient(){
shouldOverrideUrlLoading(WebView view,String url) 最常用的,比如上面的。
//在網頁上的所有加載都經過這個方法,這個函數我們可以做很多操作。
//比如獲取url,查看url.contains(“add”),進行添加操作
shouldOverrideKeyEvent(WebView view, KeyEvent event)
//重寫此方法才能夠處理在瀏覽器中的按鍵事件。
onPageStarted(WebView view,String url, Bitmap favicon)
//這個事件就是開始載入頁面調用的,我們可以設定一個loading的頁面,告訴用戶程序在等待網絡響應。
onPageFinished(WebView view,String url)
//在頁面加載結束時調用。同樣道理,我們可以關閉loading 條,切換程序動作。 onLoadResource(WebView view,String url)// 在加載頁面資源時會調用,每一個資源(比如圖片)的加載都會調用一次。
onReceivedError(WebView view, int errorCode,String description,String failingUrl)
// (報告錯誤信息)
doUpdateVisitedHistory(WebView view,String url, boolean isReload)
//(更新歷史記錄)
onFormResubmission(WebView view, Message dontResend, Message resend)
//(應用程序重新請求網頁數據)
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,String host,String realm)
//(獲取返回信息授權請求)
onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
//重寫此方法可以讓webview處理https請求。
onScaleChanged(WebView view, float oldScale, float newScale)
// (WebView發生改變時調用)
onUnhandledKeyEvent(WebView view, KeyEvent event)
//(Key事件未被加載時調用)
}
**將上面定義的WebViewClient設置給WebView:**
webView.setWebViewClient(mWebViewClient);
WebChromeClient
**WebChromeClient是輔助WebView處理Javascript的對話框,網站圖標,網站title,加載進度等 :**
方法中的代碼都是由Android端自己處理。
WebChromeClient mWebChromeClient =new WebChromeClient() {
//獲得網頁的加載進度,顯示在右上角的TextView控件中
@Override public void onProgressChanged(WebView view,int newProgress)
{
if (newProgress <100) {
String progress = newProgress +"%";
}else {
}
}
//獲取Web頁中的title用來設置自己界面中的title
//當加載出錯的時候,比如無網絡,這時onReceiveTitle中獲取的標題為 找不到該網頁,
//因此建議當觸發onReceiveError時,不要使用獲取到的title
@Override public void onReceivedTitle(WebView view, String title) {
MainActivity.this.setTitle(title);
}
@Override public void onReceivedIcon(WebView view, Bitmap icon) {
//
}
@Override public boolean onCreateWindow(WebView view,boolean isDialog,boolean isUserGesture, Message resultMsg) {
//return true;
}
@Override public void onCloseWindow(WebView window) {
}
//處理alert彈出框,html 彈框的一種方式
@OverridepublicbooleanonJsAlert(WebView view, String url, String message, JsResult result) {
//return true;
}
//處理confirm彈出框
@Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {//returntrue; }//處理prompt彈出框@OverridepublicbooleanonJsConfirm(WebView view, String url, String message, JsResult result) {//returntrue;
}
};
**同樣,將上面定義的WebChromeClient設置給WebView:**
webView.setWebChromeClient(mWebChromeClient);
調用JS代碼
WebSettings webSettings = mWebView .getSettings();
webSettings.setJavaScriptEnabled(true); mWebView.addJavascriptInterface(newInsertObj(),"jsObj");
**上面這是前提!!!**
然后實現上面的類,這個類提供了四個方法,注釋的非常清楚。
class Insert Object ends Object {
//給html提供的方法,js中可以通過:var str = window.jsObj.HtmlcallJava(); 獲取到
@Javascript Interface public String HtmlcallJava()
{
return"Html call Java";
}
//給html提供的有參函數 : window.jsObj.HtmlcallJava2("IT-homer blog"
);
@Javascript Interface public String HtmlcallJava2(final String param) {
return"Html call Java : " + param;
}
//Html給我們提供的函數
@Javascript Interface public void JavacallHtml() {
runOnUiThread(new Runnable() {
@Override public void run() {
//這里是調用方法
mWebView.loadUrl("javascript: showFromHtml()");
Toast.makeText(Html5Activity.this,"clickBtn", Toast.LENGTH_SHORT).show();
}
});
}
//Html給我們提供的有參函數
@JavascriptInterfacepublicvoidJavacallHtml2(final String param)
{
runOnUiThread(new Runnable() {
@Override public void run() {
mWebView.loadUrl("javascript: showFromHtml2('IT-homer blog')");
Toast.makeText(Html5Activity.this,"clickBtn2", Toast.LENGTH_SHORT).show();
}
});
}
}
Android 調用js有個漏洞:
http://blog.csdn.net/leehong2005/article/details/11808557
WebView的方法
前進、后退
goBack()//后退goForward()//前進goBackOrForward(intsteps)//以當前的index為起始點前進或者后退到歷史記錄中指定的steps, 如果steps為負數則為后退,正數則為前進canGoForward()//是否可以前進canGoBack()//是否可以后退
清除緩存數據:
clearCache(true);//清除網頁訪問留下的緩存,由于內核緩存是全局的因此這個方法不僅僅針對webview而是針對整個應用程序.clearHistory()//清除當前webview訪問的歷史記錄,只會webview訪問歷史記錄里的所有記錄除了當前訪問記錄.clearFormData()//這個api僅僅清除自動完成填充的表單數據,并不會清除WebView存儲到本地的數據。
WebView的狀態:
onResume()//激活WebView為活躍狀態,能正常執行網頁的響應onPause()//當頁面被失去焦點被切換到后臺不可見狀態,需要執行onPause動過, onPause動作通知內核暫停所有的動作,比如DOM的解析、plugin的執行、JavaScript執行。pauseTimers()//當應用程序被切換到后臺我們使用了webview, 這個方法不僅僅針對當前的webview而是全局的全應用程序的webview,它會暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。resumeTimers()//恢復pauseTimers時的動作。destroy()//銷毀,關閉了Activity時,音樂或視頻,還在播放。就必須銷毀。
但是注意:
webview調用destory時,webview仍綁定在Activity上.這是由于自定義webview構建時傳入了該Activity的context對象,因此需要先從父容器中移除webview,然后再銷毀webview:
rootLayout.removeView(webView);webView.destroy();
判斷WebView是否已經滾動到頁面底端 或者 頂端:
getScrollY() //方法返回的是當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離.
getHeight()或者getBottom() //方法都返回當前WebView這個容器的高度
getContentHeight()返回的是整個html的高度,但并不等同于當前整個頁面的高度,因為WebView有縮放功能,所以當前整個頁面的高度實際上應該是原始html的高度再乘上縮放比例.因此,更正后的結果,準確的判斷方法應該是:
if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {//已經處于底端 }if(webView.getScrollY() ==0){//處于頂端
}
避免WebView內存泄露的一些方式
1.可以將 Webview 的 Activity 新起一個進程,結束的時候直接System.exit(0);退出當前進程;
啟動新進程,主要代碼: AndroidManifest.xml 配置文件代碼如下
在新進程中啟動 Activity ,里面傳了 一個 Url:
Intent intent =newIntent("com.lyl.boon.ui.activity.htmlactivity");Bundle bundle =newBundle(); bundle.putString("url", gankDataEntity.getUrl()); intent.putExtra("bundle",bundle);
startActivity(intent);
然后在 Html5Activity 的onDestory() 最后加上 System.exit(0); 殺死當前進程。
2.不能在xml中定義 Webview ,而是在需要的時候創建,并且Context使用 getApplicationgContext(),如下代碼:
LinearLayout.LayoutParamsparams =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mWebView =new WebView(getApplicationContext()); mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
3.在 Activity 銷毀的時候,可以先讓 WebView 加載null內容,然后移除 WebView,再銷毀 WebView,最后置空。
代碼如下:
@OverrideprotectedvoidonDestroy() {if (mWebView !=null) { mWebView.loadDataWithBaseURL(null,"","text/html","utf-8",null); mWebView.clearHistory(); ((ViewGroup) mWebView.getParent()).removeView(mWebView); mWebView.destroy(); mWebView =null; }super.onDestroy();
}
返回鍵
返回上一次瀏覽的頁面
public booleanonKeyDown(int keyCode, KeyEventevent) {if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack();returntrue; }return super.onKeyDown(keyCode,event);
}
有一個非常不錯的 Html5Activity 加載類帖出來:
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;import android.view.KeyEvent;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.lyl.test.R;
public class Html5Activity extends AppCompatActivity {
private String mUrl;
private LinearLayout mLayout;
private WebView mWebView;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web);
Bundle bundle = getIntent().getBundleExtra("bundle");
mUrl = bundle.getString("url");
Log.d("Url:", mUrl);
mLayout = (LinearLayout) findViewById(R.id.web_layout);
LinearLayout.LayoutParams params =new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView =new WebView(getApplicationContext());
mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
WebSettings mWebSettings = mWebView.getSettings();
mWebSettings.setSupportZoom(true);
mWebSettings.setLoadWithOverviewMode(true);
mWebSettings.setUseWideViewPort(true);
mWebSettings.setDefaultTextEncodingName("utf-8");
mWebSettings.setLoadsImagesAutomatically(true);
//調用JS方法.安卓版本大于17,加上注解 @JavascriptInterface
mWebSettings.setJavaScriptEnabled(true);
saveData(mWebSettings);
newWin(mWebSettings);
mWebView.setWebChromeClient(webChromeClient);
mWebView.setWebViewClient(webViewClient);
mWebView.loadUrl(mUrl);
}
/** * 多窗口的問題 */
private void newWin(WebSettings mWebSettings) {
//html中的_bank標簽就是新建窗口打開,有時會打不開,需要加以下
//然后 復寫 WebChromeClient的onCreateWindow方法
mWebSettings.setSupportMultipleWindows(true);
mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
}
/** * HTML5數據存儲 */
private void saveData(WebSettings mWebSettings) {
//有時候網頁需要自己保存一些關鍵數據,Android WebView 需要自己設置
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setAppCacheEnabled(true);
String appCachePath =getApplicationContext().getCacheDir().getAbsolutePath();
mWebSettings.setAppCachePath(appCachePath);
}
WebViewClient webViewClient =new WebViewClient(){
/**
* 多頁面在同一個WebView中打開,就是不新建activity或者調用系統瀏覽器打開
*/
@Override public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
};
WebChromeClient webChromeClient =new WebChromeClient() {
//=========HTML5定位=========
//需要先加入權限//////
@Override public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
@Override public void onGeolocationPermissionsHidePrompt() {
super.onGeolocationPermissionsHidePrompt();
}
@Override public void onGeolocationPermissionsShowPrompt(final String origin,final GeolocationPermissions.Callback callback) {
callback.invoke(origin,true,false);
//注意個函數,第二個參數就是是否同意定位權限,第三個是是否希望內核記住
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
//=========HTML5定位===================
//=========多窗口的問題===========================
@OverridepublicbooleanonCreateWindow(WebView view,boolean isDialog,boolean isUserGesture, Message resultMsg) {
WebView.WebViewTransport transport = (WebView.WebViewTransport)
resultMsg.obj;
transport.setWebView(mWebView);
resultMsg.sendToTarget();
return true;
}
//=========多窗口的問題=========================
};
@OverridepublicbooleanonKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack())
{
mWebView.goBack();returntrue;
}
return super.onKeyDown(keyCode, event);
}