414

http://blog.csdn.net/liuhe688/article/details/6549263

WebView是Android中一个非常实用的组件,它和Safai、Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面。使用WebView开发软件有一下几个优点:

1.可以打开远程URL页面,也可以加载本地HTML数据;

2.可以无缝的在java和javascript之间进行交互操作;

3.高度的定制性,可根据开发者的需要进行多样性定制。

下面就通过例子来介绍一下WebView的使用方法。

我们先建一个webview项目,项目结构如左图:

在这个项目中,我们会先进入MainActivity这个导航界面(上边右图),通过点击不同按钮转向不同的Activity,下面分别简单介绍一下这几个Activity的所要演示的功能:

LoadActivity:主要演示加载网络页面和WebView的一些基本设置;

CaptureActivity:主要演示WebView的截图的功能;

FileActivity:主要演示访问本地文件的功能;

JSActivity:主要演示WebView对JS的支持以及JS和Java之间的互相调用;

接下来,我们会逐一分析各个Activity的相关信息:

LoadActivity:

与之对应的布局文件为load.xml,演示效果如下:

我们在文本框中输入URL,然后点击“load”按钮,然后由WebView加载相应的页面,在加载过程中,根据加载进度更新窗口的进度条。由于布局相对简单,我们主要来看一下LoadActivity.java的代码:

[java] view plaincopy

  1. package com.scott.webview;
  2. import android.app.Activity;

  3. import android.os.Bundle;

  4. import android.view.KeyEvent;

  5. import android.view.View;

  6. import android.view.Window;

  7. import android.webkit.WebChromeClient;

  8. import android.webkit.WebSettings;

  9. import android.webkit.WebView;

  10. import android.webkit.WebViewClient;

  11. import android.widget.Button;

  12. import android.widget.EditText;
  13. public class LoadActivity extends Activity {
  14. private WebView webView;
  15. @Override

  16. protected void onCreate(Bundle savedInstanceState) {

  17. super.onCreate(savedInstanceState);
  18. //设置窗口风格为进度条

  19. getWindow().requestFeature(Window.FEATURE_PROGRESS);
  20. setContentView(R.layout.load);
  21. webView = (WebView) findViewById(R.id.webView);
  22. WebSettings settings = webView.getSettings();

  23. settings.setSupportZoom(true);          //支持缩放

  24. settings.setBuiltInZoomControls(true);  //启用内置缩放装置

  25. settings.setJavaScriptEnabled(true);    //启用JS脚本
  26. webView.setWebViewClient(new WebViewClient() {

  27. //当点击链接时,希望覆盖而不是打开新窗口

  28. @Override

  29. public boolean shouldOverrideUrlLoading(WebView view, String url) {

  30. view.loadUrl(url);  //加载新的url

  31. return true;    //返回true,代表事件已处理,事件流到此终止

  32. }

  33. });
  34. //点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)

  35. webView.setOnKeyListener(new View.OnKeyListener() {

  36. @Override

  37. public boolean onKey(View v, int keyCode, KeyEvent event) {

  38. if (event.getAction() == KeyEvent.ACTION_DOWN) {

  39. if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {

  40. webView.goBack();   //后退

  41. return true;    //已处理

  42. }

  43. }

  44. return false;

  45. }

  46. });
  47. webView.setWebChromeClient(new WebChromeClient() {

  48. //当WebView进度改变时更新窗口进度

  49. @Override

  50. public void onProgressChanged(WebView view, int newProgress) {

  51. //Activity的进度范围在0到10000之间,所以这里要乘以100

  52. LoadActivity.this.setProgress(newProgress * 100);

  53. }

  54. });
  55. final EditText url = (EditText) findViewById(R.id.url);
  56. Button loadURL = (Button) findViewById(R.id.loadURL);

  57. loadURL.setOnClickListener(new View.OnClickListener() {

  58. @Override

  59. public void onClick(View v) {

  60. webView.loadUrl(url.getText().toString());  //加载url

  61. webView.requestFocus(); //获取焦点

  62. }

  63. });

  64. }

  65. }

可以看到,我们使用loadUrl方法加载一个url页面,然后重写WebChromeClient的onProgressChanged方法更新进度条。loadUrl方法除了能加载远程页面,还能加载本地的文件:

[java] view plaincopy

  1. //加载assets中的html文件

  2. webView.loadUrl("file:///android_asset/index.html");

  3. //加载sdcard中的html文件

  4. webView.loadUrl("file:///mnt/sdcard/index.html");

这些都会在后边的示例中使用到。

CaptureActivity:

与之对应的布局文件为capture.xml,也比较简单,它的演示效果如下:

记得在AndroidManifest.xml中加入对sdcard的写权限:

[xhtml] view plaincopy

  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

截图成功后,在/mnt/sdcard目录下会生成一个当前网页的截图,如图:

我们导出一下,看看是不是当前的网页界面:

整个过程操作已经完成了,让我们来看一下CaptureActivity.java的代码:

[java] view plaincopy

  1. package com.scott.webview;
  2. import java.io.FileOutputStream;
  3. import android.app.Activity;

  4. import android.graphics.Bitmap;

  5. import android.graphics.Canvas;

  6. import android.graphics.Picture;

  7. import android.os.Bundle;

  8. import android.util.Log;

  9. import android.view.View;

  10. import android.webkit.WebView;

  11. import android.widget.Button;

  12. import android.widget.Toast;
  13. public class CaptureActivity extends Activity {
  14. private static final String TAG = "CAPTURE";
  15. private WebView webView;
  16. @Override

  17. protected void onCreate(Bundle savedInstanceState) {

  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.capture);
  20. webView = (WebView) findViewById(R.id.webView);

  21. webView.loadUrl("http://www.baidu.com");
  22. Button capture = (Button) findViewById(R.id.capture);

  23. capture.setOnClickListener(new View.OnClickListener() {

  24. @Override

  25. public void onClick(View v) {

  26. //取得android.graphics.Picture实例

  27. Picture picture = webView.capturePicture();

  28. int width = picture.getWidth();

  29. int height = picture.getHeight();

  30. if (width > 0 && height > 0) {

  31. //创建指定高宽的Bitmap对象

  32. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

  33. //创建Canvas,并以bitmap为绘制目标

  34. Canvas canvas = new Canvas(bitmap);

  35. //将WebView影像绘制在Canvas上

  36. picture.draw(canvas);

  37. try {

  38. String fileName = "/sdcard/webview_capture.jpg";

  39. FileOutputStream fos = new FileOutputStream(fileName);

  40. //压缩bitmap到输出流中

  41. bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);

  42. fos.close();

  43. Toast.makeText(CaptureActivity.this, "CAPTURE SUCCESS", Toast.LENGTH_LONG).show();

  44. } catch (Exception e) {

  45. Log.e(TAG, e.getMessage());

  46. }

  47. }

  48. }

  49. });

  50. }

  51. }

FileActivity:

这个界面没有布局文件,在代码中完成,它将演示如何加载一段html代码,并应用刚才生成的网页截图,效果如下图:

在这个过程中,我们加载了截图,并给图加上了红色的边框,CaptureActivity.java代码如下:

[java] view plaincopy

  1. package com.scott.webview;
  2. import android.app.Activity;

  3. import android.os.Bundle;

  4. import android.webkit.WebView;
  5. public class FileActivity extends Activity {

  6. @Override

  7. protected void onCreate(Bundle savedInstanceState) {

  8. super.onCreate(savedInstanceState);

  9. WebView webView = new WebView(this);

  10. webView.getSettings().setAllowFileAccess(true); //默认就是启用的,这里只是强调一下

  11. String baseURL = "file:///mnt/sdcard/";         //根URL

  12. String html = "<html><body>"

  13. + "<h3>image from sdcard:<h3><br/>"

  14. + "<img src=‘webview_capture.jpg‘ style=‘border:2px solid #FF0000;‘/>"

  15. + "</body></html>";

  16. //加载相对于根URL下的数据,historyUrl设为null即可

  17. webView.loadDataWithBaseURL(baseURL, html, "text/html", "utf-8", null);
  18. setContentView(webView);

  19. }

  20. }

如果将html文本保存成.html文件,放于/mnt/sdcard目录下,然后用以下方式加载也能达到相同的效果:

[java] view plaincopy

  1. webView.loadUrl("file:///mnt/sdcard/index.html");

接下来是最后一个示例:JSActivity,也是最精彩的示例,演示如何在JS和Java之间通信,我们来看一下演示过程,如图:

然后谈谈我们的执行过程,我们需要在Java代码中设置WebView的一些事件的响应,比如alert、confirm以及prompt这些JS事件,让它们按照我们的要求呈现给用户,然后我们需要定义一个Java和JS之间的接口对象,当我们加载完一个html文档后,根据这个对象的接口名称就可以在文档的JS代码中轻松的调用这个接口对象的方法,执行Java代码,我们也可以在Java端执行html文档中的JS代码。下面我们将通过代码来证实这一过程:

JSActivity.java代码如下:

[java] view plaincopy

  1. package com.scott.webview;
  2. import java.util.ArrayList;

  3. import java.util.List;
  4. import android.app.Activity;

  5. import android.app.AlertDialog;

  6. import android.content.DialogInterface;

  7. import android.os.Bundle;

  8. import android.os.Handler;

  9. import android.os.Message;

  10. import android.util.Log;

  11. import android.view.LayoutInflater;

  12. import android.view.View;

  13. import android.view.Window;

  14. import android.webkit.JsPromptResult;

  15. import android.webkit.JsResult;

  16. import android.webkit.WebChromeClient;

  17. import android.webkit.WebView;

  18. import android.widget.EditText;

  19. import android.widget.Toast;
  20. public class JSActivity extends Activity {
  21. private static final String TAG = "JSActivity";
  22. private  WebView webView;
  23. private Handler handler = new Handler() {

  24. public void handleMessage(android.os.Message msg) {

  25. int index = msg.arg1;

  26. JSActivity.this.setProgress(index * 1000);

  27. };

  28. };
  29. @Override

  30. public void onCreate(Bundle savedInstanceState) {

  31. super.onCreate(savedInstanceState);
  32. getWindow().requestFeature(Window.FEATURE_PROGRESS);
  33. webView = new WebView(this);
  34. webView.getSettings().setJavaScriptEnabled(true);
  35. webView.addJavascriptInterface(new Object() {

  36. @SuppressWarnings("unused")

  37. public List<String> getList() {

  38. List<String> list = new ArrayList<String>();

  39. for (int i = 0; i <= 10; i++) {

  40. try {

  41. Thread.sleep(200);

  42. } catch (InterruptedException e) {

  43. Log.e(TAG, "error:" + e.getMessage());

  44. }

  45. list.add("current index is: " + i);
  46. //不能在此直接调用Activity.setProgress,否则会报以下错误

  47. //Only the original thread that created a view hierarchy can touch its views.

  48. Message msg = handler.obtainMessage();

  49. msg.arg1 = i;

  50. handler.sendMessage(msg);

  51. }

  52. success();

  53. return list;

  54. }
  55. public void success() {

  56. //由Java代码调用JS函数

  57. webView.loadUrl("javascript:success(‘congratulations‘)");

  58. }

  59. }, "bridge");
  60. webView.setWebChromeClient(new WebChromeClient() {

  61. @Override

  62. public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {

  63. new AlertDialog.Builder(JSActivity.this)

  64. .setTitle("alert")

  65. .setMessage(message)

  66. .setPositiveButton("YES", new DialogInterface.OnClickListener() {

  67. @Override

  68. public void onClick(DialogInterface dialog, int which) {

  69. //处理结果为确定状态 同时唤醒WebCore线程

  70. result.confirm();

  71. }

  72. }).create().show();

  73. return true;    //已处理

  74. }
  75. @Override

  76. public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {

  77. new AlertDialog.Builder(JSActivity.this)

  78. .setTitle("confirm")

  79. .setMessage(message)

  80. .setPositiveButton("YES", new DialogInterface.OnClickListener() {

  81. @Override

  82. public void onClick(DialogInterface dialog, int which) {

  83. Toast.makeText(JSActivity.this, "you clicked yes", 0).show();

  84. result.confirm();

  85. }

  86. })

  87. .setNegativeButton("NO", new DialogInterface.OnClickListener() {

  88. @Override

  89. public void onClick(DialogInterface dialog, int which) {

  90. //处理结果为取消状态 同时唤醒WebCore线程

  91. result.cancel();

  92. }

  93. }).create().show();

  94. return true;

  95. }
  96. @Override

  97. public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,

  98. final JsPromptResult result) {

  99. LayoutInflater inflater = getLayoutInflater();

  100. View prompt = inflater.inflate(R.layout.prompt, null);

  101. final EditText text = (EditText) prompt.findViewById(R.id.prompt_input);

  102. text.setHint(defaultValue);
  103. new AlertDialog.Builder(JSActivity.this)

  104. .setTitle("prompt")

  105. .setView(prompt)

  106. .setPositiveButton("YES", new DialogInterface.OnClickListener() {

  107. @Override

  108. public void onClick(DialogInterface dialog, int which) {

  109. //记录结果

  110. result.confirm(text.getText().toString());

  111. }

  112. })

  113. .setNegativeButton("NO", new DialogInterface.OnClickListener() {

  114. @Override

  115. public void onClick(DialogInterface dialog, int which) {

  116. result.cancel();

  117. }

  118. }).create().show();

  119. return true;

  120. }

  121. });
  122. //加载assets中的html文件

  123. webView.loadUrl("file:///android_asset/index.html");
  124. setContentView(webView);

  125. }

  126. }

需要注意的是,在重写onJsAlert、onJsConfirm、onJsPrompt这几个方法中,不要忘了用JsResult.confirm()或JsResult.cancel()处理结果,否则页面就不能再响应接下的事件了,关于这一点,我们可以看一下JsResult的代码:

[c-sharp] view plaincopy

  1. /**

  2. * Handle a confirmation response from the user.

  3. */

  4. public final void confirm() {

  5. mResult = true;

  6. wakeUp();

  7. }
  8. /**

  9. * Handle the result if the user cancelled the dialog.

  10. */

  11. public final void cancel() {

  12. mResult = false;

  13. wakeUp();

  14. }

可以看到confirm和cancel方法都涉及到了一个wakeUp方法,这个方法主要作用是唤醒WebCore线程,定义如下:

[c-sharp] view plaincopy

  1. /* Wake up the WebCore thread. */

  2. protected final void wakeUp() {

  3. if (mReady) {

  4. synchronized (mProxy) {

  5. mProxy.notify();

  6. }

  7. } else {

  8. mTriedToNotifyBeforeReady = true;

  9. }

  10. }

所以朋友们如果要重写这几个方法时要切记处理JsResult这个对象实例。

我们在处理onJsPrompt时,使用了自定义的界面,加载的是/res/layout/prompt.xml,定义如下:

[xhtml] view plaincopy

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <LinearLayout

  3. xmlns:android="http://schemas.android.com/apk/res/android"

  4. android:layout_width="wrap_content"

  5. android:layout_height="wrap_content">

  6. <EditText

  7. android:id="@+id/prompt_input"

  8. android:layout_width="fill_parent"

  9. android:layout_height="wrap_content"/>

  10. </LinearLayout>

在JSActivity.java代码中,我们注意到WebView组件加载了assets中的index.html,它包含与Java交互的JS代码,如下:

[xhtml] view plaincopy

  1. <html>

  2. <head>

  3. <script type="text/javascript">

  4. function doAlert() {

  5. alert("hello!");

  6. }
  7. function doConfirm() {

  8. confirm("are you sure?");

  9. }
  10. function doPrompt() {

  11. var val = prompt("what‘s your name?");

  12. if (val) {

  13. alert("your name is:" + val);

  14. }

  15. }
  16. function getList() {

  17. //使用java和javascript的接口bridge的方法获取集合

  18. var list = window.bridge.getList();

  19. var result = document.getElementById("result");

  20. for (var i = 0; i < list.size(); i++) {

  21. var div = document.createElement("div");

  22. div.innerHTML = list.get(i).toString();

  23. result.appendChild(div);

  24. }

  25. }
  26. function success(msg) {

  27. alert(msg);

  28. }

  29. </script>

  30. </head>

  31. <body background="black">

  32. <input type="button" value="alert" onclick="doAlert()"/><br/>

  33. <input type="button" value="confirm" onclick="doConfirm()"/><br/>

  34. <input type="button" value="prompt" onclick="doPrompt()"/><br/>

  35. <input type="button" value="getList" onclick="getList()"/><br/>

  36. <div id="result"></div>

  37. </body>

  38. </html>

WebView的优点还不止这些,希望在今后的时间里,再和大家分享WebView的相关技术,也希望这篇文章能够对初识WebView的朋友们带来帮助。

时间: 2024-08-27 13:14:55

414的相关文章

nginx出现 “414 request-uri too large”

1.  nginx出现  "414 request-uri too large" 解决方法:在nginx.conf的配置文件中,修改如下配置:     client_header_buffer_size 512k;     large_client_header_buffers 4 512k; 2.   错误日志报 "upstream sent too big header while reading response header from upstream" 解

nginx 414 Request-URI Too Large

症状 nginx 414 Request-URI Too Large #客户端请求头缓冲区大小,如果请求头总长度大于小于128k,则使用此缓冲区, #请求头总长度大于128k时使用large_client_header_buffers设置的缓存区client_header_buffer_size 128k; #large_client_header_buffers 指令参数4为个数,128k为大小,默认是8k.申请4个128k.large_client_header_buffers 4 128k

【42】414. Third Maximum Number

414. Third Maximum Number Description Submission Solutions Add to List Total Accepted: 20624 Total Submissions: 76932 Difficulty: Easy Contributors: ZengRed, 1337c0d3r Given a non-empty array of integers, return the third maximum number in this array

乐视414截胡传统家电旺季五一黄金周带来的启示

今日一份中怡康线下周度监测数据刷爆了朋友圈,原因是数据显示,五一期间液晶市场零售量同比下降9.2%,零售额同比下降23.8%.五一当周(18周)零售量更是连续三年同比下滑,2016年达到下滑以来的历史新低,降幅29.5%.这个数据既在意料之外也在情理之中,其中关键原因是人造促销节点的增多,在2016年4月,乐视.天猫.苏宁.国美分别启动了较大规模的促销活动,在带动四月市场总销量的同时,也提前透支了五一当周的需求.尤其是乐视在线上的表现,以22.3%的品牌份额稳居第一.简单的理解就是:乐视414"

2017-3-4 leetcode 414

虽说周末要早起来着,但是日子过得有点奇怪,一不小心就忘掉了... leetcode414 https://leetcode.com/problems/third-maximum-number/?tab=Description leetcode leetcode ====================================== 414说的是给你n个数字(无序,有重复),输出第三大的数,如果没有,输出最大的,使用O(n)的算法.注意,你的排序中不能有相同的,也就是说如果输入2,3,2,3

SHU 414 - 字符串进制转换

题目链接:http://acmoj.shu.edu.cn/problem/414/ 网上拉了个进制转换模板过来,因为数组开的太小一直WA,难受-- 1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 10000 4 int t[MAXN],A[MAXN],n; 5 char OldData[MAXN],NewData[MAXN]; //转换前.后的数据 6 int olds,news; //转换前.后的进制 7 void tr

nginx优化:URI过长或request header过大导致400或414报错

当http 的URI太长或者request header过大时会报414 Request URI too large或400 bad request错误. 解决方法: 修改两个参数 参数一: #client_header_buffer_size:客户端请求头缓冲区大小,client_header_buffer_size 128k;#如果请求头总长度大于小于128k,则使用此缓冲区 参数二: #large_client_header_buffers:请求头总长度大于128k时使用large_cli

memcached-win32-1.4.4-14 help doc

memcached-win32-1.4.4-14 cmd打开命令窗口,转到解压的目录,输入 “memcached.exe -d install”. 使用telnet命令 验证缓存服务器是否可用.telnet 127.0.0.1 11211stats 参数介绍 1. 以上的安装和启动都是在默认环境下进行的,在安装时可设置如下参数: -p 监听的端口 -l 连接的IP地址, 默认是本机 -d start 启动memcached服务 -d restart 重起memcached服务 -d stop|s

4-14 学习

4-14 学习心得 一.UITabBarController的viewControllers属性 UITabBarController本身并不会显示任何视图,如果要显示视图则必须设置其viewControllers属性(它默认显示viewControllers[0])这个属性是一个数组,它维护了所有UITabBarController的子视图.为了尽可能减少视图之间的耦合,所有的UITabBarController的子视图的相关标题.图标等信息均由子视图自己控制,UITabBarControll

Could not load file or assembly &#39;Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, ...

使用oracle数据库一个多月依赖这问题一直都得不到解决,最近任务不是很忙了,所以决定把这问题解决掉.写一篇文章做记录. 以上错误主要是net程序oracle数据库使用了Microsoft Enterprise Library 5.0 类库访问oracle数据库,其具有优秀的访问不通数据库的能力.使用方法不对也同样出现错误.解决办法是下载http://www.microsoft.com/en-us/download/confirmation.aspx?id=15104最新的类库并安装,安装后到安