在Android中可以通过WebView控件来进行Web浏览。本文将对WebView相关的知识进行一个介绍。
一、WebView介绍
WebView支持标准的浏览器特性,比如浏览历史、缩放、JavaScript。
1、可以通过WebSettings来定制WebView,通过 webview.getSettings()获取WebSettings的实例。主要有以下方法:
(1)webview.getSettings().setJavaScriptEnabled(true);传入true启用JavaScript的支持。默认是关闭的,不启用可能导致网页无法正常显示。
(2)webView.getSettings().supportMultipleWindows();传入true启用多窗口支持。
(3)webView.getSettings().setBuiltInZoomControls(true);传入true可以进行缩放。
(4)webView.getSettings().setTextZoom();设置web内容的缩放百分比。
reload():刷新或重载当前页面
goBack():在浏览历史记录中回退一步
canGoBack():检查是否有历史记录可供回退
goForward():在浏览历史记录中前进一步
canGoForward():检查是否有历史记录可供前进
clearCache():清除浏览器缓存
clearHistory():清除浏览器历史
requestFocus(): 如果不设置的话会出现不能弹出软件盘的问题
loadUrl(String url):加载路径为URL的网址
postUrl(String url, byte[] postData): 加载页面使用Post方式,postData为参数
stopLoading(): 停止加载
requestFocus(): 如果不设置的话会出现不能弹出软件盘的问题
setScrollBarStyle():设置滚动条风格,如webview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);在内容内部显示滚动条
3、WebViewClient类
webViewClient主要帮助webView处理各种通知请求事件。
如果你的网页中有网页链接,在默认情况下,android会调用默认的浏览器打开它。如果想要用自己的webView打开,则需要用到WebViewClient类。具体用法如下:
wv.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
if(url.contains("tel")){
new Handler().call(url.substring(4));
return true;
}
view.loadUrl(url);
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
// if (url.contains("http")) {
// Toast.makeText(getActivity(), "enter baidu",
// Toast.LENGTH_LONG).show();
// } else {
// Toast.makeText(getActivity(), "enter your page",
// Toast.LENGTH_LONG).show();
// }
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
// if (url.contains("http")) {
// Toast.makeText(getActivity(), "baidu finish loading",
// Toast.LENGTH_LONG).show();
// } else {
// Toast.makeText(getActivity(), "your page finish loading",
// Toast.LENGTH_LONG).show();
// }
}
});
翻译过来就是:在WebView中加载一个新的URL的时候给宿主程序一个机会去控制这个URL的加载。如果没有设置WebViewClient,默认情况下将通过Activity Manager去选择一个优先级高的handler,如果设置了WebViewClient,如果返回true,宿主程序处理这个URL的加载,如果返回false,当前的webView处理URL的加载。(外语水平有限,如有错误欢迎指正)。
所以,可以根据URL来判断是想要系统默认程序处理这个URL,还是想要WebView来处理。
onPageStarted()、onPageFinished() :页面开始加载/结束加载时调用;
onReceiveError():产生错误时触发
4、WebChromeClient类
主要辅助WebView处理Javascript的对话框、进度条等。由于WebView上alert,Prompt,Confirm上是无效,所以需要定制WebChromeClient处理弹出,从而获取网页中的JS,比如使用AlertDialog进行显示。
wv.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url,
String message, JsResult result) {
// TODO Auto-generated method stub
new AlertDialog.Builder(getActivity()).setMessage(message).setNegativeButton("YES", null).show();
return true;
}
});
5、JavaScript和Android相互调用
5.1 android调用JavaScript
wv.loadUrl("javascript:showMsg('aaaa')");
代码很简单,但是一定要记得设置如下代码,否则操作无反应:
wv.getSettings().setJavaScriptEnabled(true);
5.2 JavaScript调用android
wv.addJavascriptInterface(new Object(){
@JavascriptInterface
public void call(String num){
Intent intent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+num));
startActivity(intent);
}
@JavascriptInterface
public void show(){
Toast.makeText(getActivity(), "enter show!", Toast.LENGTH_LONG).show();
}
}, "handler");
html代码:
<a href="javascript:window.handler.call('456')">call 456</a>
这里特别要注意的是:在每个方法上面一定要加上:@JavascriptInterface,否则会报错误:Uncaught TypeError。
4、使用WebViewFragment类
WebViewFragment是一个包含了WebView的fragment,可以用getWebView()方法获取WebView,其他方法与上文一致。父类是
android.app.Fragment,所以兼容性不是很好,min version is 11。当然,可以自定义一个WebViewFragment,继承android.support.v4.app.Fragment就可解决兼容性问题。
二、WebView缓存问题
当加载html页面时,会在/data/data/应用package目录下生成database与cache两个文件夹如下图如示:
请求的url记录是保存在webviewCache.db,而url的内容是保存在webviewCache文件夹下。
下面通过一个例子来说明如何生成及读取缓存:
当使用webView加载html页面时,会在/data/data/应用package目录下生成database与cache两个文件夹,请求的url记录是保存在webviewCache.db,而url的内容是保存在webviewCache文件夹下。
我们可以使用SQLiteDatabase读取数据库获取资源路径,然后根据资源路径读取缓存。当然,也可以删除这些缓存。注意:在刪除文件夹的时候要先删除文件夹下的文件,否则无法删除。
package com.dream.webviewcachedemo;
import java.io.File;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import android.os.Build;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment implements OnClickListener{
public PlaceholderFragment() {
}
View rootView ;
Button showBtn;
Button deleteBtn;
WebView wv;
String url="file:///android_asset/index.html";
AlertDialog dialog;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
@SuppressLint("NewApi")
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
showBtn=(Button)rootView.findViewById(R.id.btn_main_showImg);
showBtn.setOnClickListener(this);
deleteBtn=(Button)rootView.findViewById(R.id.btn_main_delete);
deleteBtn.setOnClickListener(this);
wv=(WebView)rootView.findViewById(R.id.wv_main_website);
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().supportMultipleWindows();
wv.getSettings().setSupportZoom(true);
wv.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return false;
}
});
wv.loadUrl(url);
initDialog();
}
private void initDialog() {
AlertDialog.Builder builder=new AlertDialog.Builder(getActivity()).setTitle("Message").setNegativeButton("YES", null);
dialog=builder.create();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_main_showImg:
getCache();
break;
case R.id.btn_main_delete:
deleteCache();
default:
break;
}
}
private void deleteCache() {
//delete the .db file
try {
getActivity().deleteDatabase("webviewCache.db");
getActivity().deleteDatabase("webview.db");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//delete cache file
File file=new File(getActivity().getCacheDir()+"/webviewCache");
try {
deleteFile(file);
dialog.setMessage("Delete Cache Success");
dialog.show();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void deleteFile(File file) {
if(file.exists()){
if(file.isFile()){
file.delete();
return;
}
if(file.isDirectory()){
File[] childFiles=file.listFiles();
if(childFiles==null || childFiles.length==0){
file.delete();
return;
}
for(File f : childFiles){
deleteFile(f);
}
file.delete();
}
}
}
private void getCache() {
try {
SQLiteDatabase db=getActivity().openOrCreateDatabase("webviewCache.db",MODE_PRIVATE , null);
Cursor c=db.query("cache", null, null, null, null, null, null);
if(c!=null){
//get the first row
c.moveToFirst();
//get filepath
String filepath=c.getString(c.getColumnIndex("filepath"));
Log.i("System.out", "filepath is :"+filepath);
//find the image by filepath
Bitmap bm=BitmapFactory.decodeFile(getActivity().getCacheDir()+"/webviewCache/"+filepath);
if(bm==null){
showNoCache();
return;
}
ImageView iv=new ImageView(getActivity());
iv.setImageBitmap(bm);
new AlertDialog.Builder(getActivity()).setView(iv).setNegativeButton("YES", null).show();
c.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
showNoCache();
e.printStackTrace();
}
}
private void showNoCache() {
dialog.setMessage("No cache");
dialog.show();
}
}
}
三、资料
WebView缓存 http://www.cnblogs.com/linjiqin/archive/2011/10/28/2227943.html
WebView缓存机制详解 http://blog.youkuaiyun.com/t12x3456/article/details/13745553