`
444878909
  • 浏览: 639476 次
文章分类
社区版块
存档分类
最新评论

一片WebView的好文章,直接拿过来 = =

 
阅读更多

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的代码:

  1. packagecom.scott.webview;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.view.KeyEvent;
  5. importandroid.view.View;
  6. importandroid.view.Window;
  7. importandroid.webkit.WebChromeClient;
  8. importandroid.webkit.WebSettings;
  9. importandroid.webkit.WebView;
  10. importandroid.webkit.WebViewClient;
  11. importandroid.widget.Button;
  12. importandroid.widget.EditText;
  13. publicclassLoadActivityextendsActivity{
  14. privateWebViewwebView;
  15. @Override
  16. protectedvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. //设置窗口风格为进度条
  19. getWindow().requestFeature(Window.FEATURE_PROGRESS);
  20. setContentView(R.layout.load);
  21. webView=(WebView)findViewById(R.id.webView);
  22. WebSettingssettings=webView.getSettings();
  23. settings.setSupportZoom(true);//支持缩放
  24. settings.setBuiltInZoomControls(true);//启用内置缩放装置
  25. settings.setJavaScriptEnabled(true);//启用JS脚本
  26. webView.setWebViewClient(newWebViewClient(){
  27. //当点击链接时,希望覆盖而不是打开新窗口
  28. @Override
  29. publicbooleanshouldOverrideUrlLoading(WebViewview,Stringurl){
  30. view.loadUrl(url);//加载新的url
  31. returntrue;//返回true,代表事件已处理,事件流到此终止
  32. }
  33. });
  34. //点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)
  35. webView.setOnKeyListener(newView.OnKeyListener(){
  36. @Override
  37. publicbooleanonKey(Viewv,intkeyCode,KeyEventevent){
  38. if(event.getAction()==KeyEvent.ACTION_DOWN){
  39. if(keyCode==KeyEvent.KEYCODE_BACK&&webView.canGoBack()){
  40. webView.goBack();//后退
  41. returntrue;//已处理
  42. }
  43. }
  44. returnfalse;
  45. }
  46. });
  47. webView.setWebChromeClient(newWebChromeClient(){
  48. //当WebView进度改变时更新窗口进度
  49. @Override
  50. publicvoidonProgressChanged(WebViewview,intnewProgress){
  51. //Activity的进度范围在0到10000之间,所以这里要乘以100
  52. LoadActivity.this.setProgress(newProgress*100);
  53. }
  54. });
  55. finalEditTexturl=(EditText)findViewById(R.id.url);
  56. ButtonloadURL=(Button)findViewById(R.id.loadURL);
  57. loadURL.setOnClickListener(newView.OnClickListener(){
  58. @Override
  59. publicvoidonClick(Viewv){
  60. webView.loadUrl(url.getText().toString());//加载url
  61. webView.requestFocus();//获取焦点
  62. }
  63. });
  64. }
  65. }

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

  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的写权限:

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

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

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

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

  1. packagecom.scott.webview;
  2. importjava.io.FileOutputStream;
  3. importandroid.app.Activity;
  4. importandroid.graphics.Bitmap;
  5. importandroid.graphics.Canvas;
  6. importandroid.graphics.Picture;
  7. importandroid.os.Bundle;
  8. importandroid.util.Log;
  9. importandroid.view.View;
  10. importandroid.webkit.WebView;
  11. importandroid.widget.Button;
  12. importandroid.widget.Toast;
  13. publicclassCaptureActivityextendsActivity{
  14. privatestaticfinalStringTAG="CAPTURE";
  15. privateWebViewwebView;
  16. @Override
  17. protectedvoidonCreate(BundlesavedInstanceState){
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.capture);
  20. webView=(WebView)findViewById(R.id.webView);
  21. webView.loadUrl("http://www.baidu.com");
  22. Buttoncapture=(Button)findViewById(R.id.capture);
  23. capture.setOnClickListener(newView.OnClickListener(){
  24. @Override
  25. publicvoidonClick(Viewv){
  26. //取得android.graphics.Picture实例
  27. Picturepicture=webView.capturePicture();
  28. intwidth=picture.getWidth();
  29. intheight=picture.getHeight();
  30. if(width>0&&height>0){
  31. //创建指定高宽的Bitmap对象
  32. Bitmapbitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
  33. //创建Canvas,并以bitmap为绘制目标
  34. Canvascanvas=newCanvas(bitmap);
  35. //将WebView影像绘制在Canvas上
  36. picture.draw(canvas);
  37. try{
  38. StringfileName="/sdcard/webview_capture.jpg";
  39. FileOutputStreamfos=newFileOutputStream(fileName);
  40. //压缩bitmap到输出流中
  41. bitmap.compress(Bitmap.CompressFormat.PNG,90,fos);
  42. fos.close();
  43. Toast.makeText(CaptureActivity.this,"CAPTURESUCCESS",Toast.LENGTH_LONG).show();
  44. }catch(Exceptione){
  45. Log.e(TAG,e.getMessage());
  46. }
  47. }
  48. }
  49. });
  50. }
  51. }

FileActivity:

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

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

  1. packagecom.scott.webview;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.webkit.WebView;
  5. publicclassFileActivityextendsActivity{
  6. @Override
  7. protectedvoidonCreate(BundlesavedInstanceState){
  8. super.onCreate(savedInstanceState);
  9. WebViewwebView=newWebView(this);
  10. webView.getSettings().setAllowFileAccess(true);//默认就是启用的,这里只是强调一下
  11. StringbaseURL="file:///mnt/sdcard/";//根URL
  12. Stringhtml="<html><body>"
  13. +"<h3>imagefromsdcard:<h3><br/>"
  14. +"<imgsrc='webview_capture.jpg'style='border:2pxsolid#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目录下,然后用以下方式加载也能达到相同的效果:

  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代码如下:

  1. packagecom.scott.webview;
  2. importjava.util.ArrayList;
  3. importjava.util.List;
  4. importandroid.app.Activity;
  5. importandroid.app.AlertDialog;
  6. importandroid.content.DialogInterface;
  7. importandroid.os.Bundle;
  8. importandroid.os.Handler;
  9. importandroid.os.Message;
  10. importandroid.util.Log;
  11. importandroid.view.LayoutInflater;
  12. importandroid.view.View;
  13. importandroid.view.Window;
  14. importandroid.webkit.JsPromptResult;
  15. importandroid.webkit.JsResult;
  16. importandroid.webkit.WebChromeClient;
  17. importandroid.webkit.WebView;
  18. importandroid.widget.EditText;
  19. importandroid.widget.Toast;
  20. publicclassJSActivityextendsActivity{
  21. privatestaticfinalStringTAG="JSActivity";
  22. privateWebViewwebView;
  23. privateHandlerhandler=newHandler(){
  24. publicvoidhandleMessage(android.os.Messagemsg){
  25. intindex=msg.arg1;
  26. JSActivity.this.setProgress(index*1000);
  27. };
  28. };
  29. @Override
  30. publicvoidonCreate(BundlesavedInstanceState){
  31. super.onCreate(savedInstanceState);
  32. getWindow().requestFeature(Window.FEATURE_PROGRESS);
  33. webView=newWebView(this);
  34. webView.getSettings().setJavaScriptEnabled(true);
  35. webView.addJavascriptInterface(newObject(){
  36. @SuppressWarnings("unused")
  37. publicList<String>getList(){
  38. List<String>list=newArrayList<String>();
  39. for(inti=0;i<=10;i++){
  40. try{
  41. Thread.sleep(200);
  42. }catch(InterruptedExceptione){
  43. Log.e(TAG,"error:"+e.getMessage());
  44. }
  45. list.add("currentindexis:"+i);
  46. //不能在此直接调用Activity.setProgress,否则会报以下错误
  47. //Onlytheoriginalthreadthatcreatedaviewhierarchycantouchitsviews.
  48. Messagemsg=handler.obtainMessage();
  49. msg.arg1=i;
  50. handler.sendMessage(msg);
  51. }
  52. success();
  53. returnlist;
  54. }
  55. publicvoidsuccess(){
  56. //由Java代码调用JS函数
  57. webView.loadUrl("javascript:success('congratulations')");
  58. }
  59. },"bridge");
  60. webView.setWebChromeClient(newWebChromeClient(){
  61. @Override
  62. publicbooleanonJsAlert(WebViewview,Stringurl,Stringmessage,finalJsResultresult){
  63. newAlertDialog.Builder(JSActivity.this)
  64. .setTitle("alert")
  65. .setMessage(message)
  66. .setPositiveButton("YES",newDialogInterface.OnClickListener(){
  67. @Override
  68. publicvoidonClick(DialogInterfacedialog,intwhich){
  69. //处理结果为确定状态同时唤醒WebCore线程
  70. result.confirm();
  71. }
  72. }).create().show();
  73. returntrue;//已处理
  74. }
  75. @Override
  76. publicbooleanonJsConfirm(WebViewview,Stringurl,Stringmessage,finalJsResultresult){
  77. newAlertDialog.Builder(JSActivity.this)
  78. .setTitle("confirm")
  79. .setMessage(message)
  80. .setPositiveButton("YES",newDialogInterface.OnClickListener(){
  81. @Override
  82. publicvoidonClick(DialogInterfacedialog,intwhich){
  83. Toast.makeText(JSActivity.this,"youclickedyes",0).show();
  84. result.confirm();
  85. }
  86. })
  87. .setNegativeButton("NO",newDialogInterface.OnClickListener(){
  88. @Override
  89. publicvoidonClick(DialogInterfacedialog,intwhich){
  90. //处理结果为取消状态同时唤醒WebCore线程
  91. result.cancel();
  92. }
  93. }).create().show();
  94. returntrue;
  95. }
  96. @Override
  97. publicbooleanonJsPrompt(WebViewview,Stringurl,Stringmessage,StringdefaultValue,
  98. finalJsPromptResultresult){
  99. LayoutInflaterinflater=getLayoutInflater();
  100. Viewprompt=inflater.inflate(R.layout.prompt,null);
  101. finalEditTexttext=(EditText)prompt.findViewById(R.id.prompt_input);
  102. text.setHint(defaultValue);
  103. newAlertDialog.Builder(JSActivity.this)
  104. .setTitle("prompt")
  105. .setView(prompt)
  106. .setPositiveButton("YES",newDialogInterface.OnClickListener(){
  107. @Override
  108. publicvoidonClick(DialogInterfacedialog,intwhich){
  109. //记录结果
  110. result.confirm(text.getText().toString());
  111. }
  112. })
  113. .setNegativeButton("NO",newDialogInterface.OnClickListener(){
  114. @Override
  115. publicvoidonClick(DialogInterfacedialog,intwhich){
  116. result.cancel();
  117. }
  118. }).create().show();
  119. returntrue;
  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. *Handleaconfirmationresponsefromtheuser.
  3. */
  4. publicfinalvoidconfirm(){
  5. mResult=true;
  6. wakeUp();
  7. }
  8. /**
  9. *Handletheresultiftheusercancelledthedialog.
  10. */
  11. publicfinalvoidcancel(){
  12. mResult=false;
  13. wakeUp();
  14. }

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

[c-sharp]view plaincopy
  1. /*WakeuptheWebCorethread.*/
  2. protectedfinalvoidwakeUp(){
  3. if(mReady){
  4. synchronized(mProxy){
  5. mProxy.notify();
  6. }
  7. }else{
  8. mTriedToNotifyBeforeReady=true;
  9. }
  10. }

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

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

  1. <?xmlversion="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代码,如下:

  1. <html>
  2. <head>
  3. <scripttype="text/javascript">
  4. functiondoAlert(){
  5. alert("hello!");
  6. }
  7. functiondoConfirm(){
  8. confirm("areyousure?");
  9. }
  10. functiondoPrompt(){
  11. varval=prompt("what'syourname?");
  12. if(val){
  13. alert("yournameis:"+val);
  14. }
  15. }
  16. functiongetList(){
  17. //使用java和javascript的接口bridge的方法获取集合
  18. varlist=window.bridge.getList();
  19. varresult=document.getElementById("result");
  20. for(vari=0;i<list.size();i++){
  21. vardiv=document.createElement("div");
  22. div.innerHTML=list.get(i).toString();
  23. result.appendChild(div);
  24. }
  25. }
  26. functionsuccess(msg){
  27. alert(msg);
  28. }
  29. </script>
  30. </head>
  31. <bodybackground="black">
  32. <inputtype="button"value="alert"onclick="doAlert()"/><br/>
  33. <inputtype="button"value="confirm"onclick="doConfirm()"/><br/>
  34. <inputtype="button"value="prompt"onclick="doPrompt()"/><br/>
  35. <inputtype="button"value="getList"onclick="getList()"/><br/>
  36. <divid="result"></div>
  37. </body>
  38. </html>

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


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics