webview兩種實現方法,覆蓋onKeyDown()方法javascript
緩存html
一、要實現JS代碼與Java代碼互相通訊,須要經過Android的WebView控件,在視圖佈局界面引入該控件,代碼以下:android
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" /> </RelativeLayout>
二、準備html界面:web
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript"> function show(jsondata){ var jsonobjs = eval(jsondata); var table=document.getElementById("personTable"); for(var y=0;y<jsonobjs.length;y++){ var tr = table.insertRow(table.rows.length); var td1=tr.insertCell(0); td1.align="center"; var td2=tr.insertCell(1); td2.align="center"; td1.innerHTML=jsonobjs[y].name; td2.innerHTML="<a href='javascript:contact.call(\""+jsonobjs[y].phone+"\")'>"+jsonobjs[y].phone+"</a>"; } } </script> </head> <body onload="javascript:contact.showContacts()"> <table border="0" cellspacing="0" id="personTable" width="100%"> <tr> <td width="35%" align="right">姓名</td><td align="center">電話</td> </tr> </table> <a href="javascript:window.location.reload()">刷新</a> </body> </html>
在上述代碼中相似"javascript:contact.showContacts()"這樣的寫法,它表明的意思是調用javascript對象contact的showContacts方法。而對象contact就要從後臺java代碼中獲取。json
三、在java代碼中建立javascript對象:瀏覽器
package com.example.html; import java.util.List; import org.json.JSONArray; import org.json.JSONObject; import com.example.service.ContactService; import android.net.Uri; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.webkit.WebView; public class MainActivity extends Activity { private WebView webView; private ContactService contactService; @SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" }) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = (WebView) this.findViewById(R.id.webView); webView.loadUrl("file:///android_asset/contact.html");// 加載html文件 webView.getSettings().setJavaScriptEnabled(true);// 啓用javascript // 第一個參數在javascript中的一個對象,第二個參數在javascript中當前對象的變量 webView.addJavascriptInterface(new JSObject(), "contact"); contactService = new ContactService(); } private final class JSObject { // 顯示聯繫人列表,對於高版本的須要用@JavascriptInterface註釋,不然調不到該方法 @JavascriptInterfacepublic void showContacts() { try { List<ContactService.Contact> contacts = contactService.getContacts(); JSONArray jsonArray = new JSONArray(); for (ContactService.Contact contact : contacts) { JSONObject object = new JSONObject(); object.put("name", contact.getUsername()); object.put("phone", contact.getPhone()); jsonArray.put(object); } String json = jsonArray.toString(); // 後臺調用前臺html文件中javascript的方法show webView.loadUrl("javascript:show('" + json + "')"); } catch (Exception e) { e.printStackTrace(); } } // 打電話 @SuppressWarnings("unused") public void call(String phone) { Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone)); startActivity(intent); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } }
3.1 javascript調用java方法:緩存
上面的內部類JSObject 能夠當作是javascript的對象,而contact能夠當作是該對象的名稱,內部的方法showContacts能夠當作javascript對象的方法。所以對於在上述代碼中"javascript:contact.showContacts()"的寫法表示,執行內部類JSObject網絡
中的方法showContacts。app
3.2 java調用javascript方法:
能夠經過WebView控件調用,例如:webView.loadUrl("javascript:show('" + json + "')")則表示,調用javascript中的show方法。
2、緩存
WebView中存在着兩種緩存:網頁數據緩存(存儲打開過的頁面及資源)、H5緩存(即appcache)。 1、網頁緩存 1、緩存構成 /data/data/package_name/cache/ /data/data/package_name/database/webview.db /data/data/package_name/database/webviewCache.db 2、緩存模式 較難理解的是如下兩個模式: LOAD_DEFAULT,根據cache-control決定是否從網絡上取數據。 LOAD_CACHE_ELSE_NETWORK,只要本地有,不管是否過時,或者no-cache,都使用緩存中的數據。 如:m.taobao.com的cache-control爲no-cache,在模式LOAD_DEFAULT下,不管如何都會從網絡上取數據,若是沒有網絡,就會出現錯誤頁面;在LOAD_CACHE_ELSE_NETWORK模式下,不管是否有網絡,只要本地有緩存,都使用緩存。本地沒有緩存時才從網絡上獲取。 m.sina.com.cn的cache-control爲max-age=60,在兩種模式下都使用本地緩存數據。 總結:根據以上兩種模式,建議緩存策略爲,判斷是否有網絡,有的話,使用LOAD_DEFAULT,無網絡時,使用LOAD_CACHE_ELSE_NETWORK。 3、清除緩存 clearCache(boolean)。 CacheManager.clear。高版本中須要調用隱藏API。 4、控制大小 無系統API支持。 可選方式:定時統計緩存大小、按時間順序刪除緩存。 2、H5緩存 1、緩存構成 根據setAppCachePath(String appCachePath)提供的路徑,在H5使用緩存過程當中生成的緩存文件。 2、緩存模式 無模式選擇,經過setAppCacheEnabled(boolean flag)設置是否打開。默認關閉,即,H5的緩存沒法使用。 3、清除緩存 找到調用setAppCachePath(String appCachePath)設置緩存的路徑,把它下面的文件所有刪除就OK了。 4、控制大小 經過setAppCacheMaxSize(long appCacheMaxSize)設置緩存最大容量,默認爲Max Integer。 同時,可能經過覆蓋WebChromeClient.onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)來設置緩存超過先前設置的最大容量時的策略。 3、參考網址 如下地址有關於H5緩存的一些內幕,如每一個Application只調用一次WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()被忽略等一系列問題,須要仔細閱讀和實驗。 http://code.google.com/p/android/issues/detail?id=24180
三 webview一些參數和事件的設置:
1) 設置WebView基本信息: webview.getSettings().setJavaScriptEnabled(true); //若是訪問的頁面中有Javascript,則webview必須設置支持Javascript。 requestFocus();//觸摸焦點起做用 this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);// 取消滾動條 2) 設置WevView要顯示的網頁: 互聯網用:webView.loadUrl("http://www.google.com"); 本地文件用:webView.loadUrl("file:///android_asset/XX.html"); 本地文件存放在:assets文件中 3) 若是但願點擊連接由本身處理,而不是新開Android的系統browser中響應該連接。給WebView添加一個事件監聽對象(WebViewClient)並重寫其中的一些方法: shouldOverrideUrlLoading:對網頁中超連接按鈕的響應。當按下某個鏈接時WebViewClient會調用這個方法,並傳遞參數:按下的url。好比當webview內嵌網頁的某個數字被點擊時,它會自動認爲這是一個電話請求, 會傳遞url:tel:123,若是你不但願如此可經過重寫shouldOverrideUrlLoading函數解決: 4) 另外還有其餘一些可重寫的方法 4.1 接收到 Http 請求的事件 onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) 4.2 打開連接前的事件 public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } 這個函數咱們能夠作不少操做,好比咱們讀取到某些特殊的URL,因而就能夠不打開地址,取消這個操做,進行預先定義的其餘操做,這對一個程序是很是必要的。 4.3 載入頁面完成的事件 public void onPageFinished(WebView view, String url){ } 一樣道理,咱們知道一個頁面載入完成,因而咱們能夠關閉loading條,切換程序動做。 4.4 載入頁面開始的事件 public void onPageStarted(WebView view, String url, Bitmap favicon) { } 這個事件就是開始載入頁面調用的,一般咱們能夠在這設定一個loading的頁面,告訴用戶程序在等待網絡響應。 經過這幾個事件,咱們能夠很輕鬆的控制程序操做,一邊用着瀏覽器顯示內容,一邊監控着用戶操做實現咱們須要的各類顯示方式,同時能夠防止用戶產生誤操做。 5) 若是用webview點連接看了不少頁之後,若是不作任何處理,點擊系統「Back」鍵,整個瀏覽器會調用finish()而結束自身,若是但願瀏覽的網頁回退而不是退出瀏覽器,須要在當前Activity中處理並消費掉該Back事件。 覆蓋Activity類的onKeyDown(int keyCoder,KeyEvent event)方法。 public boolean onKeyDown(int keyCoder,KeyEvent event){ if(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){ webview.goBack(); //goBack()表示返回webView的上一頁面 return true; } return false; }
支付寶網頁支付
/** * 網頁支付 * @author libin * */ public class AlipayWebActivity extends Activity { private WebView mWebView; private static final String TAG = "AlipayWebActivity"; protected static final int PAY_SUCCESS = 20; protected static final int LOAD_FINISH_CODE = 40; private static final int DEFAULT_CODE = 50;
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.web); FactoryUtil.getInstance().addActivity(this); mWebView = (WebView) findViewById(R.id.webview); mWebView.setBackgroundColor(0); initial(); } @SuppressLint({"SetJavaScriptEnabled", "HandlerLeak"}) @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void initial() { String url = getIntent().getStringExtra("url"); LogUtil.i(TAG, url); WebSettings webSettings = mWebView.getSettings(); mWebView.requestFocus(); webSettings.setJavaScriptEnabled(true); mWebView.setFocusable(true); webSettings.setBuiltInZoomControls(true); mWebView.setScrollBarStyle(0); if (MobileUtil.getMobileVersion() > 11) { mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } mWebView.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int newProgress) { LogUtil.i(TAG, "newProgress: " + newProgress); if (newProgress == 100) { mUihandler.sendEmptyMessage(LOAD_FINISH_CODE); } super.onProgressChanged(view, newProgress); } }); mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { LogUtil.i(TAG, "URL : " + url); loadUrl(view, url); return true;//中止在當前界面 } public void onPageFinished(WebView view, String url) { LogUtil.i(TAG, "onPageFinished" + url); //trade_status : TRADE_FINISHED if (url.contains("&cmd=success&ptype=url")) { BaseDialogUtil.alertDialog(AlipayWebActivity.this, "提示信息", "支付成功", false, new BaseDialogUtil.DialogOnClickListener() { @Override public void positive(DialogInterface dialoginterface, int id) { FactoryUtil.getInstance().exit(); } @Override public void negative(DialogInterface dialog, int id) { } }); } super.onPageFinished(view, url); } public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); LogUtil.i(TAG, "onPageStarted" + url); } }); loadUrl(mWebView, url); } @SuppressLint("HandlerLeak") private Handler mUihandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case PAY_SUCCESS: clearCache(); FactoryUtil.getInstance().exit(); break; case LOAD_FINISH_CODE: dissDialogGamm(); break; case DEFAULT_CODE: showProgress(AlipayWebActivity.this); } super.handleMessage(msg); } }; private void loadUrl(final WebView webView, final String url) { mUihandler.sendEmptyMessage(DEFAULT_CODE); webView.loadUrl(url); } public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { mWebView.goBack(); return true; } else if (keyCode == KeyEvent.KEYCODE_BACK) { onBackPressed(); return true; } return super.onKeyDown(keyCode, event); } private void clearCache() { mWebView.clearCache(true); mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); finish(); } }