第14章 网络编程及Internet应用

tb教学录像:1小时36分钟)

Google公司以网络搜索引擎起家,通过大胆的创意和不断的研发努力,目前已经成为网络世界的巨头,而出自于Google之手的Android平台,在网络编程和Internet应用上也是非常优秀的。本章将对Android中的网络编程和Internet应用的相关知识进行详细介绍。

通过阅读本章,您可以:

★ 掌握使用HttpURLConnection访问网络的方法

★ 掌握使用HttpClient访问网络的方法

★ 掌握如何使用WebView组件浏览网页

★ 掌握在WebView组件中加载HTML代码的方法

★ 掌握让WebView组件支持JavaScript的方法

14.1 通过HTTP访问网络

tb教学录像:光盘\TM\lx\14\通过HTTP访问网络.exe

随着智能手机和平板电脑等移动终端设备的迅速发展,现在的Internet已经不再只是传统的有线互联网,还包括移动互联网。同有线互联网一样,移动互联网也可以使用HTTP访问网络。在Android中,针对HTTP进行网络通信的方法主要有两种:一种是使用HttpURLConnection实现;另一种是使用HttpClient实现,下面分别进行介绍。

14.1.1 使用HttpURLConnection访问网络

HttpURLConnection类位于java.net包中,用于发送HTTP请求和获取HTTP响应。由于该类是抽象类,不能直接实例化对象,则需要使用URL的openConnection()方法来获得。例如,要创建一个http://www.mingribook.com网站对应的HttpURLConnection对象,可以使用下面的代码:

  1. URL url = new URL("http://www.mingribook.com/");
  2. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

说明:通过openConnection()方法创建的HttpURLConnection对象,并没有真正执行连接操作,只是创建了一个新的实例,在进行连接前,还可以设置一些属性。例如,连接超时的时间和请求方式等。

创建了HttpURLConnection对象后,就可以使用该对象发送HTTP请求了。HTTP请求通常分为GET请求和POST请求两种,下面分别进行介绍。

  1. 发送GET请求

使用HttpURLConnection对象发送请求时,默认发送的就是GET请求。因此,发送GET请求比较简单,只需要在指定连接地址时,先将要传递的参数通过“?参数名=参数值”进行传递(多个参数间使用英文半角的逗号分隔。例如,要传递用户名和E-mail地址两个参数,可以使用?user=wgh,email= wgh717@sohu.com实现),然后获取流中的数据,并关闭连接即可。

下面通过一个具体的实例来说明如何使用HttpURLConnection发送GET请求。

例14.1 在Eclipse中创建Android项目,名称为14.1,实现向服务器发送GET请求,并获取服务器的响应结果。(实例位置:光盘\TM\sl\14\14.1)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后在默认添加的线性布局管理器中添加一个id为content的编辑框(用于输入微博内容)以及一个“发表”按钮,再添加一个滚动视图,并在该视图中添加一个线性布局管理器,最后还需要在该线性布局管理器中添加一个文本框,用于显示从服务器上读取的微博内容,关键代码如下:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="fill_parent"
  3. android:layout_height="fill_parent"
  4. android:gravity="center_horizontal"
  5. android:orientation="vertical" >
  6. <EditText
  7. android:id="@+id/content"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content" />
  10. <Button
  11. android:id="@+id/button"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="@string/button" />
  15. <ScrollView
  16. android:id="@+id/scrollView1"
  17. android:layout_width="match_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_weight="1" >
  20. <LinearLayout
  21. android:id="@+id/linearLayout1"
  22. android:layout_width="match_parent"
  23. android:layout_height="match_parent" >
  24. <TextView
  25. android:id="@+id/result"
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content"
  28. android:layout_weight="1" />
  29. </LinearLayout>
  30. </ScrollView>
  31. </LinearLayout>

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private EditText content; //声明一个输入文本内容的编辑框对象
  2. private Button button; //声明一个“发表”按钮对象
  3. private Handler handler; //声明一个Handler对象
  4. private String result = ""; //声明一个代表显示内容的字符串
  5. private TextView resultTV; //声明一个显示结果的文本框对象

(3)编写一个无返回值的send()方法,用于建立一个HTTP连接,并将输入的内容发送到Web服务器上,再读取服务器的处理结果,具体代码如下:

  1. public void send() {
  2. String target="";
  3. target = "http://192.168.1.66:8081/blog/index.jsp?content="
  4. +base64(content.getText().toString().trim()); //要访问的URL地址
  5. URL url;
  6. try {
  7. url = new URL(target); //创建URL对象
  8. HttpURLConnection urlConn = (HttpURLConnection) url
  9. .openConnection(); //创建一个HTTP连接
  10. InputStreamReader in = new InputStreamReader(
  11. urlConn.getInputStream()); //获得读取的内容
  12. BufferedReader buffer = new BufferedReader(in); //获取输入流对象
  13. String inputLine = null;
  14. //通过循环逐行读取输入流中的内容
  15. while ((inputLine = buffer.readLine()) != null) {
  16. result += inputLine + "\n";
  17. }
  18. in.close(); //关闭字符输入流对象
  19. urlConn.disconnect(); //断开连接
  20. } catch (MalformedURLException e) {
  21. e.printStackTrace();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. }

(4)在应用GET方法传递中文的参数时,会产生乱码,这时可以进行Base64编码来解决乱码问题,为此,需要编写一个base64()方法,对要进行传递的参数进行Base64编码。base64()方法的具体代码如下:

  1. public String base64(String content){
  2. try {
  3. //对字符串进行Base64编码
  4. content=Base64.encodeToString(content.getBytes("utf-8"), Base64.DEFAULT);
  5. content=URLEncoder.encode(content); //对字符串进行URL编码
  6. } catch (UnsupportedEncodingException e) {
  7. e.printStackTrace(); //输出异常信息
  8. }
  9. return content;
  10. }

说明:要解决应用GET方法传递中文参数时产生乱码的问题,也可以使用Java提供的URLEncoder类来实现。

(5)在onCreate()方法中,获取布局管理器中用于输入内容的编辑框、用于显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的内容是否为空,如果为空,则给出消息提示;否则,创建一个新的线程,调用send()方法发送并读取微博信息,具体代码如下:

  1. content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
  2. resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
  3. button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
  4. //为按钮添加单击事件监听器
  5. button.setOnClickListener(new OnClickListener() {
  6. @Override
  7. public void onClick(View v) {
  8. if ("".equals(content.getText().toString())) {
  9. Toast.makeText(MainActivity.this, "请输入要发表的内容!",
  10. Toast.LENGTH_SHORT).show(); //显示消息提示
  11. return;
  12. }
  13. //创建一个新线程,用于发送并读取微博信息
  14. new Thread(new Runnable() {
  15. public void run() {
  16. send(); //发送文本内容到Web服务器,并读取
  17. Message m = handler.obtainMessage(); //获取一个Message
  18. handler.sendMessage(m); //发送消息
  19. }
  20. }).start(); //开启线程
  21. }
  22. });

(6)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空编辑器,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (result != null) {
  5. resultTV.setText(result); //显示获得的结果
  6. content.setText(""); //清空编辑框
  7. }
  8. super.handleMessage(msg);
  9. }
  10. };

(7)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为index.jsp的文件,在该文件中,首先获取参数content指定的微博信息,并保存到变量content中,然后替换变量content中的加号,这是由于在进行URL编码时,将加号转换为了%2B,最后对content进行Base64解码,并输出转码后的content变量的值,具体代码如下:

  1. <%@ page contentType="text/html; charset=utf-8" language="java" import="sun.misc.BASE64Decoder"%>
  2. <%
  3. String content="";
  4. if(request.getParameter("content")!=null){
  5. content=request.getParameter("content"); //获取输入的微博信息
  6. //替换content中的加号,这是由于在进行URL编码时,将"+"号转换为了%2B
  7. content=content.replaceAll("%2B","+");
  8. BASE64Decoder decoder=new BASE64Decoder();
  9. content=new String(decoder.decodeBuffer(content),"utf-8"); //进行Base64解码
  10. }
  11. %>
  12. <%="发表一条微博,内容如下:"%>
  13. <%=content%>

将index.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入一条微博信息,再单击“发表”按钮,在下方将显示Web服务器的处理结果。例如,输入“坚持到底就是胜利!”后,单击“发表”按钮,将显示如图14.1所示的运行结果。

438-1 图14.1 使用GET方式发表并显示微博信息

  1. 发送POST请求

由于采用GET方式发送请求只适合发送大小在1024个字节以内的数据,所以当要发送的数据较大时,就需要使用POST方式来发送请求。在Android中,使用HttpURLConnection类发送请求时,默认采用的是GET请求,如果要发送POST请求,需要通过其setRequestMethod()方法进行指定。例如,创建一个HTTP连接,并为该连接指定请求的发送方式为POST,可以使用下面的代码:

  1. HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); //创建一个HTTP连接
  2. urlConn.setRequestMethod("POST"); //指定请求方式为POST

发送POST请求要比发送GET请求复杂一些,它经常需要通过HttpURLConnection类及其父类URLConnection提供的方法设置相关内容,常用的方法如表14.1所示。

表14.1 发送POST请求时常用的方法

方 法 描 述
setDoInput(boolean newValue) 用于设置是否向连接中写入数据,如果参数值为true,表示写入数据;否则不写入数据
setDoOutput(boolean newValue) 用于设置是否从连接中读取数据,如果参数值为true,表示读取数据;否则不读取数据
setUseCaches(boolean newValue) 用于设置是否缓存数据,如果参数值为true,表示缓存数据;否则表示禁用缓存
setInstanceFollowRedirects(boolean followRedirects) 用于设置是否应该自动执行HTTP重定向,参数值为true时,表示自动执行;否则不自动执行
setRequestProperty(String field, String newValue) 用于设置一般请求属性,例如,要设置内容类型为表单数据,可以进行以下设置setRequestProperty("Content-Type","application/x-www-form-urlencoded")

下面通过一个具体的实例来介绍如何使用HttpURLConnection类发送POST请求。

例14.2 在Eclipse中创建Android项目,名称为14.2,实现向服务器发送POST请求,并获取服务器的响应结果。(实例位置:光盘\TM\sl\14\14.2)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后在默认添加的线性布局管理器中添加一个id为content的编辑框(用于输入微博内容)以及一个“发表”按钮,最后添加一个滚动视图,并在该视图中添加一个线性布局管理器,同时,还需要在该线性布局管理器中添加一个文本框,用于显示从服务器上读取的微博内容,具体代码请参见光盘。

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private EditText nickname;   //声明一个输入昵称的编辑框对象
  2. private EditText content; //声明一个输入文本内容的编辑框对象
  3. private Button button;  //声明一个"发表"按钮对象
  4. private Handler handler; //声明一个Handler对象
  5. private String result = ""; //声明一个代表显示内容的字符串
  6. private TextView resultTV; //声明一个显示结果的文本框对象

(3)编写一个无返回值的send()方法,用于建立一个HTTP连接,并使用POST方式将输入的昵称和内容发送到Web服务器上,再读取服务器处理的结果,具体代码如下:

  1. public void send() {
  2. String target = "http://192.168.1.66:8081/blog/dealPost.jsp"; //要提交的目标地址
  3. URL url;
  4. try {
  5. url = new URL(target);
  6. HttpURLConnection urlConn = (HttpURLConnection) url
  7. .openConnection(); //创建一个HTTP连接
  8. urlConn.setRequestMethod("POST"); //指定使用POST请求方式
  9. urlConn.setDoInput(true); //向连接中写入数据
  10. urlConn.setDoOutput(true); //从连接中读取数据
  11. urlConn.setUseCaches(false); //禁止缓存
  12. urlConn.setInstanceFollowRedirects(true); //自动执行HTTP重定向
  13. urlConn.setRequestProperty("Content-Type",
  14. "application/x-www-form-urlencoded"); //设置内容类型
  15. DataOutputStream out = new DataOutputStream(
  16. urlConn.getOutputStream()); //获取输出流
  17. String param = "nickname="
  18. + URLEncoder.encode(nickname.getText().toString(), "utf-8")
  19. + "&content="
  20. + URLEncoder.encode(content.getText().toString(), "utf-8"); //连接要提交的数据
  21. out.writeBytes(param); //将要传递的数据写入数据输出流
  22. out.flush(); //输出缓存
  23. out.close(); //关闭数据输出流
  24. //判断是否响应成功
  25. if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
  26. InputStreamReader in = new InputStreamReader(
  27. urlConn.getInputStream()); //获得读取的内容
  28. BufferedReader buffer = new BufferedReader(in); //获取输入流对象
  29. String inputLine = null;
  30. while ((inputLine = buffer.readLine()) != null) {
  31. result += inputLine + "\n";
  32. }
  33. in.close(); //关闭字符输入流
  34. }
  35. urlConn.disconnect(); //断开连接
  36. } catch (MalformedURLException e) {
  37. e.printStackTrace();
  38. } catch (IOException e) {
  39. e.printStackTrace();
  40. }
  41. }

说明:在设置要提交的数据时,如果包括多个参数,则各个参数间使用“&”进行连接。

(4)在onCreate()方法中,获取布局管理器中添加的昵称编辑框、内容编辑框、显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的昵称和内容是否为空,只要有一个为空,就给出消息提示;否则,创建一个新的线程,用于调用send()方法发送并读取服务器处理后的微博信息,具体代码如下:

  1. content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
  2. resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
  3. nickname=(EditText)findViewById(R.id.nickname); //获取输入昵称的EditText组件
  4. button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
  5. //为按钮添加单击事件监听器
  6. button.setOnClickListener(new OnClickListener() {
  7. @Override
  8. public void onClick(View v) {
  9. if ("".equals(content.getText().toString())) {
  10. Toast.makeText(MainActivity.this, "请输入要发表的内容!",Toast.LENGTH_SHORT).show();
  11. return;
  12. }
  13. //创建一个新线程,用于发送并读取微博信息
  14. new Thread(new Runnable() {
  15. public void run() {
  16. send();
  17. Message m = handler.obtainMessage(); //获取一个Message
  18. handler.sendMessage(m); //发送消息
  19. }
  20. }).start(); //开启线程
  21. }
  22. });

(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空昵称和内容编辑器,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (result != null) {
  5. resultTV.setText(result); //显示获得的结果
  6. content.setText(""); //清空内容编辑框
  7. nickname.setText(""); //清空昵称编辑框
  8. }
  9. super.handleMessage(msg);
  10. }
  11. };

(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为dealPost.jsp的文件,在该文件中,首先获取参数nickname和content指定的昵称和微博信息,并保存到相应的变量中,然后当昵称和微博内容均不为空时,对其进行转码,并获取系统时间,同时组合微博信息输出到页面上,具体代码如下:

  1. <%@ page contentType="text/html; charset=utf-8" language="java" %>
  2. <%
  3. String content=request.getParameter("content"); //获取输入的微博信息
  4. String nickname=request.getParameter("nickname"); //获取输入的昵称
  5. if(content!=null && nickname!=null){
  6. nickname=new String(nickname.getBytes("iso-8859-1"),"utf-8"); //对昵称进行转码
  7. content=new String(content.getBytes("iso-8859-1"),"utf-8"); //对内容进行转码
  8. String date=new java.util.Date().toLocaleString(); //获取系统时间
  9. %>
  10. <%="[ "+nickname+" ]于 "+date+" 发表一条微博,内容如下:"%>
  11. <%=content%>
  12. <% }%>

将dealPost.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入昵称和微博信息,单击“发表”按钮,在下方将显示Web服务器的处理结果。例如,输入昵称为“无语”、微博内容为“坚持到底就是胜利!”后,单击“发表”按钮,将显示如图14.2所示的运行结果。

441-1 图14.2 应用POST方式发表一条微博信息

14.1.2 使用HttpClient访问网络

在14.1.1节中,介绍了使用java.net包中的HttpURLConnection类来访问网络,在一般情况下,如果只需要到某个简单页面提交请求并获取服务器的响应,完全可以使用该技术来实现。不过,对于比较复杂的联网操作,使用HttpURLConnection类就不一定能满足要求,这时,可以使用Apache组织提供的HttpClient项目来实现。在Android中,已经成功地集成了HttpClient,所以可以直接在Android中使用HttpClient来访问网络。

HttpClient实际上是对Java提供的访问网络的方法进行了封装。HttpURLConnection类中的输入/输出流操作,在HttpClient中被统一封装成了HttpGet、HttpPost和HttpResponse类,这样,就简化了操作。其中,HttpGet类代表发送GET请求;HttpPost类代表发送POST请求;HttpResponse类代表处理响应的对象。

同使用HttpURLConnection类一样,使用HttpClient发送HTTP请求也可以分为发送GET请求和POST请求两种,下面分别进行介绍。

  1. 发送GET请求

同HttpURLConnection类一样,使用HttpClient发送GET请求的方法也比较简单,大致可以分为以下几个步骤。

(1)创建HttpClient对象。

(2)创建HttpGet对象。

(3)如果需要发送请求参数,可以直接将要发送的参数连接到URL地址中,也可以调用HttpGet的setParams()方法来添加请求参数。

(4)调用HttpClient对象的execute()方法发送请求。执行该方法将返回一个HttpResponse对象。

(5)调用HttpResponse的getEntity()方法,可获得包含服务器响应内容的HttpEntity对象,通过该对象可以获取服务器的响应内容。

下面通过一个具体的实例来说明如何使用HttpClient来发送GET请求。

例14.3 在Eclipse中创建Android项目,名称为14.3,实现使用HttpClient向服务器发送GET请求,并获取服务器的响应结果。(实例位置:光盘\TM\sl\14\14.3)

(1)修改新建项目的res\layout目录下的布局文件main.xml,在默认添加的TextView组件的上方添加一个Button组件,并设置其显示文本为“发送GET请求”,然后将TextView组件的id属性修改为result。具体代码请参见光盘。

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private Button button; //声明一个“发送GET请求”按钮对象
  2. private Handler handler; //声明一个Handler对象
  3. private String result = ""; //声明一个代表显示结果的字符串
  4. private TextView resultTV; //声明一个显示结果的文本框对象

(3)编写一个无返回值的send()方法,用于建立一个发送GET请求的HTTP连接,并将指定的参数发送到Web服务器上,再读取服务器的响应信息,具体代码如下:

  1. public void send() {
  2. String target = "http://192.168.1.66:8081/blog/deal_httpclient.jsp?param=get"; //要提交的目标地址
  3. HttpClient httpclient = new DefaultHttpClient(); //创建HttpClient对象
  4. HttpGet httpRequest = new HttpGet(target); //创建HttpGet连接对象
  5. HttpResponse httpResponse;
  6. try {
  7. httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
  8. if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
  9. result = EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
  10. }else{
  11. result="请求失败!";
  12. }
  13. } catch (ClientProtocolException e) {
  14. e.printStackTrace(); //输出异常信息
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }

(4)在onCreate()方法中,获取布局管理器中添加的用于显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新的线程,并且在重写的run()方法中,首先调用send()方法发送并读取微博信息,然后获取一个Message对象,并调用其sendMessage()方法发送消息,具体代码如下:

  1. resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
  2. button = (Button) findViewById(R.id.button); //获取“发送GET请求”按钮组件
  3. //为按钮添加单击事件监听器
  4. button.setOnClickListener(new OnClickListener() {
  5. @Override
  6. public void onClick(View v) {
  7.  
  8. //创建一个新线程,用于发送并获取GET请求
  9. new Thread(new Runnable() {
  10. public void run() {
  11. send();
  12. Message m = handler.obtainMessage(); //获取一个Message
  13. handler.sendMessage(m); //发送消息
  14. }
  15. }).start(); //开启线程
  16. }
  17. });

(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (result != null) {
  5. resultTV.setText(result); //显示获得的结果
  6. }
  7. super.handleMessage(msg);
  8. }
  9. };

(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为deal_httpclient.jsp的文件,在该文件中,首先获取参数param的值,如果该值不为空,则判断其值是否为get,如果是get,则输出文字“发送GET请求成功!”,具体代码如下:

  1. <%@ page contentType="text/html; charset=utf-8" language="java" %>
  2. <%
  3. String param=request.getParameter("param"); //获取参数值
  4. if(!"".equals(param) || param!=null){
  5. if("get".equals(param)){
  6. out.println("发送GET请求成功!");
  7. }
  8. }
  9. %>

将deal_httpclient.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,单击“发送GET请求”按钮,在下方将显示Web服务器的处理结果。如果请求发送成功,则显示如图14.3所示的运行结果;否则,显示文字“请求失败!”。

444-1 图14.3 应用HttpClient发送GET请求

  1. 发送POST请求

同使用HttpURLConnection类发送请求一样,对于复杂的请求数据,也需要使用POST方式发送。使用HttpClient发送POST请求大致可以分为以下几个步骤。

(1)创建HttpClient对象。

(2)创建HttpPost对象。

(3)如果需要发送请求参数,可以调用HttpPost的setParams()方法来添加请求参数,也可以调用setEntity()方法来设置请求参数。

(4)调用HttpClient对象的execute()方法发送请求。执行该方法将返回一个HttpResponse对象。

(5)调用HttpResponse的getEntity()方法,可获得包含服务器响应内容的HttpEntity对象,通过该对象可以获取服务器的响应内容。

下面通过一个具体的实例来说明如何使用HttpClient来发送POST请求。

例14.4 在Eclipse中创建Android项目,名称为14.4,实现应用HttpClient向服务器发送POST请求,并获取服务器的响应结果。(实例位置:光盘\TM\sl\14\14.4)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后在默认添加的线性布局管理器中添加一个id为content的编辑框(用于输入微博内容)以及一个“发表”按钮,再添加一个滚动视图,并在该视图中添加一个线性布局管理器,最后还需要在该线性布局管理器中添加一个文本框,用于显示从服务器上读取的微博内容,具体代码请参见光盘。

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private EditText nickname; //声明一个输入昵称的编辑框对象
  2. private EditText content; //声明一个输入文本内容的编辑框对象
  3. private Button button; //声明一个“发表”按钮对象
  4. private Handler handler; //声明一个Handler对象
  5. private String result = ""; //声明一个代表显示内容的字符串
  6. private TextView resultTV; //声明一个显示结果的文本框对象

(3)编写一个无返回值的send()方法,用于建立一个使用POST请求方式的HTTP连接,并将输入的昵称和微博内容发送到Web服务器上,再读取服务器处理的结果,具体代码如下:

  1. public void send() {
  2. String target = "http://192.168.1.66:8081/blog/deal_httpclient.jsp"; //要提交的目标地址
  3. HttpClient httpclient = new DefaultHttpClient(); //创建HttpClient对象
  4. HttpPost httpRequest = new HttpPost(target); //创建HttpPost对象
  5. //将要传递的参数保存到List集合中
  6. List<NameValuePair> params = new ArrayList<NameValuePair>();
  7. params.add(new BasicNameValuePair("param", "post")); //标记参数
  8. params.add(new BasicNameValuePair("nickname", nickname.getText().toString())); //昵称
  9. params.add(new BasicNameValuePair("content", content.getText().toString())); //内容
  10. try {
  11. httpRequest.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //设置编码方式
  12. HttpResponse httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
  13. if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ //如果请求成功
  14. result += EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
  15.  
  16. }else{
  17. result = "请求失败!";
  18. }
  19. } catch (UnsupportedEncodingException e1) {
  20. e1.printStackTrace(); //输出异常信息
  21. } catch (ClientProtocolException e) {
  22. e.printStackTrace(); //输出异常信息
  23. } catch (IOException e) {
  24. e.printStackTrace(); //输出异常信息
  25. }
  26. }

(4)在onCreate()方法中,获取布局管理器中添加的昵称编辑框、内容编辑框、显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的昵称和内容是否为空,只要有一个为空,就给出消息提示;否则,创建一个新的线程,调用send()方法发送并读取服务器处理后的微博信息,具体代码如下:

  1. content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
  2. resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
  3. nickname=(EditText)findViewById(R.id.nickname); //获取输入昵称的EditText组件
  4. button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
  5. //为按钮添加单击事件监听器
  6. button.setOnClickListener(new OnClickListener() {
  7. @Override
  8. public void onClick(View v) {
  9. if ("".equals(content.getText().toString())) {
  10. Toast.makeText(MainActivity.this, "请输入要发表的内容!",Toast.LENGTH_SHORT).show();
  11. return;
  12. }
  13. //创建一个新线程,用于发送并读取微博信息
  14. new Thread(new Runnable() {
  15. public void run() {
  16. send();
  17. Message m = handler.obtainMessage(); //获取一个Message
  18. handler.sendMessage(m); //发送消息
  19. }
  20. }).start(); //开启线程
  21. }
  22. });

(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空昵称和内容编辑器,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (result != null) {
  5. resultTV.setText(result); //显示获得的结果
  6. content.setText(""); //清空内容编辑框
  7. nickname.setText(""); //清空昵称编辑框
  8. }
  9. super.handleMessage(msg);
  10. }
  11. };

(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里仍然使用例14.3中创建的deal_httpclient.jsp文件,在该文件的if语句的结尾处添加一个else if语句,用于处理当请求参数param的值为post的情况。关键代码如下:

  1. else if("post".equals(param)){
  2. String content=request.getParameter("content"); //获取输入的微博信息
  3. String nickname=request.getParameter("nickname"); //获取输入昵称
  4. if(content!=null && nickname!=null){
  5. nickname=new String(nickname.getBytes("iso-8859-1"),"utf-8"); //对昵称进行转码
  6. content=new String(content.getBytes("iso-8859-1"),"utf-8"); //对内容进行转码
  7. String date=new java.util.Date().toLocaleString(); //获取系统时间
  8. out.println("[ "+nickname+" ]于 "+date+" 发表一条微博,内容如下:");
  9. out.println(content);
  10. }
  11. }

说明:在上面的代码中,首先获取参数nickname和content指定的昵称和微博信息,并保存到相应的变量中,然后当昵称和微博内容均不为空时对其进行转码,并获取系统时间,同时组合微博信息输出到页面上。

将deal_httpclient.jsp文件放到Tomcat安装路径下的webapps/blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入昵称和微博信息,单击“发表”按钮,在下方将显示Web服务器的处理结果。实例运行结果如图14.4所示。

447-1 图14.4 应用HttpClient发送POST请求

14.1.3 范例1:从指定网站下载文件

例14.5 在Eclipse中创建Android项目,名称为14.5,实现从指定网站下载文件。(实例位置:光盘\TM\sl\14\14.5)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的LinearLayout布局管理器修改为水平布局管理器,并将默认添加的TextView组件的android:id属性设置为@+id/editText_url;android:layout_weight属性设置为1;android:text属性设置为@string/defaultvalue;android:lines属性设置为1,然后在该TextView组件的下方添加一个“下载”按钮,具体代码请参见光盘。

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private EditText urlText; //下载地址编辑框
  2. private Button button; //下载按钮
  3. private Handler handler; //声明一个Handler对象
  4. private boolean flag = false; //标记是否成功的变量

(3)在onCreate()方法中,获取布局管理器中添加的下载地址编辑框和“下载”按钮,并为“下载”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新线程,用于从网络上获取文件;在重写的run()方法中,首先获取文件的下载地址,并创建一个相关的连接,然后获取输入流对象,并从下载地址中获取要下载文件的文件名及扩展名,再读取文件到一个输出流对象中,并关闭相关对象及断开连接,最后获取一个Message并发送消息,具体代码如下:

  1. urlText = (EditText) findViewById(R.id.editText_url); //获取布局管理器中添加的下载地址编辑框
  2. button = (Button) findViewById(R.id.button_go); //获取布局管理器中添加的“下载”按钮
  3. //为“下载”按钮添加单击事件监听器
  4. button.setOnClickListener(new OnClickListener() {
  5. @Override
  6. public void onClick(View v) {
  7. //创建一个新线程,用于从网络上获取文件
  8. new Thread(new Runnable() {
  9. public void run() {
  10. try {
  11. String sourceUrl = urlText.getText().toString(); //获取下载地址
  12. URL url = new URL(sourceUrl); //创建下载地址对应的URL对象
  13. HttpURLConnection urlConn = (HttpURLConnection) url
  14. .openConnection(); //创建一个连接
  15. InputStream is = urlConn.getInputStream(); //获取输入流对象
  16. if (is != null) {
  17. String expandName = sourceUrl.substring(
  18. sourceUrl.lastIndexOf(".") + 1,
  19. sourceUrl.length()).toLowerCase(); //获取文件的扩展名
  20. String fileName = sourceUrl.substring(
  21. sourceUrl.lastIndexOf("/") + 1,
  22. sourceUrl.lastIndexOf(".")); //获取文件名
  23. File file = new File("/sdcard/pictures/"
  24. + fileName + "." + expandName); //在SD卡上创建文件
  25. FileOutputStream fos = new FileOutputStream(
  26. file); //创建一个文件输出流对象
  27. byte buf[] = new byte[128]; //创建一个字节数组
  28. //读取文件到输出流对象中
  29. while (true) {
  30. int numread = is.read(buf);
  31. if (numread <= 0) {
  32. break;
  33. } else {
  34. fos.write(buf, 0, numread);
  35. }
  36. }
  37. }
  38. is.close(); //关闭输入流对象
  39. urlConn.disconnect(); //关闭连接
  40. flag = true;
  41. } catch (MalformedURLException e) {
  42. e.printStackTrace(); //输出异常信息
  43. flag = false;
  44. } catch (IOException e) {
  45. e.printStackTrace(); //输出异常信息
  46. flag = false;
  47. }
  48. Message m = handler.obtainMessage(); //获取一个Message
  49. handler.sendMessage(m); //发送消息
  50. }
  51. }).start(); //开启线程
  52. }
  53. });

(4)创建一个Handler对象,在重写的handleMessage()方法中,根据标记变量flag的值显示不同的消息提示,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (flag) {
  5. Toast.makeText(MainActivity.this, "文件下载完成!",
  6. Toast.LENGTH_SHORT).show(); //显示消息提示
  7. } else {
  8. Toast.makeText(MainActivity.this, "文件下载失败!",
  9. Toast.LENGTH_SHORT).show(); //显示消息提示
  10. }
  11. super.handleMessage(msg);
  12. }
  13. };

(5)由于在本实例中需要访问网络资源并向SD卡上写文件,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源和向SD卡上写文件的权限,具体代码如下:

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

运行本实例,在下载地址编辑框中输入要下载文件的URL地址,单击“下载”按钮,即可将指定的文件下载到SD卡上。成功的前提是指定的URL地址真实存在,并且相应的文件也存在。实例运行结果如图14.5和图14.6所示。

450-1 图14.5 从指定网站下载文件

450-2 图14.6 下载到SD卡上的文件

14.1.4 范例2:访问需要登录后才能访问的页面

例14.6 在Eclipse中创建Android项目,名称为14.6,使用HttpClient实现访问需要登录后才能访问的页面。(实例位置:光盘\TM\sl\14\14.6)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个水平布局管理器,并在该布局管理器中添加两个居中显示的按钮,分别是“访问页面”按钮和“用户登录”按钮,最后添加一个滚动视图,在该滚动视图中添加一个线性布局管理器,并在该布局管理器中添加一个TextView组件,用于显示访问结果。具体代码请参见光盘。

(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:

  1. private Button button1; //声明一个“访问页面”按钮对象
  2. private Button button2; //声明一个“用户登录”按钮对象
  3. private Handler handler; //声明一个Handler对象
  4. private String result = ""; //声明一个代表显示内容的字符串
  5. private TextView resultTV; //声明一个显示结果的文本框对象
  6. public static HttpClient httpclient; //声明一个静态的全局HttpClient对象

(3)编写一个无返回值的access()方法,用于建立一个发送GET请求的HTTP连接,并从服务器获得响应信息,具体代码如下:

  1. public void access() {
  2. String target = "http://192.168.1.66:8081/login/index.jsp"; //要提交的目标地址
  3. HttpGet httpRequest = new HttpGet(target); //创建HttpGet对象
  4. HttpResponse httpResponse;
  5. try {
  6. httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
  7. if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
  8. result = EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
  9. } else {
  10. result = "请求失败!";
  11. }
  12. } catch (ClientProtocolException e) {
  13. e.printStackTrace(); //输出异常信息
  14. } catch (IOException e) {
  15. e.printStackTrace();
  16. }
  17. }

(4)在onCreate()方法中,创建一个HttpClient对象,并获取显示结果的TextView组件和“访问页面”按钮,同时为“访问页面”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新的线程,在重写的run()方法中,首先调用access()方法向服务器发送一个GET请求,并获取响应结果,然后获取一个Message对象,并调用其sendMessage()方法发送消息,具体代码如下:

  1. httpclient = new DefaultHttpClient(); //创建HttpClient对象
  2. resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
  3. button1 = (Button) findViewById(R.id.button1); //获取“访问页面”按钮组件
  4. //为按钮添加单击事件监听器
  5. button1.setOnClickListener(new OnClickListener() {
  6. @Override
  7. public void onClick(View v) {
  8. //创建一个新线程,用于向服务器发送一个GET请求
  9. new Thread(new Runnable() {
  10. public void run() {
  11. access();
  12. Message m = handler.obtainMessage(); //获取一个Message
  13. handler.sendMessage(m); //发送消息
  14. }
  15. }).start(); //开启线程
  16. }
  17. });

(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,具体代码如下:

  1. handler = new Handler() {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. if (result != null) {
  5. resultTV.setText(result); //显示获得的结果
  6. }
  7. super.handleMessage(msg);
  8. }
  9. };

(6)获取布局管理器中添加的“用户登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建一个Intent对象,并启动一个新的带返回结果的Activity,具体代码如下:

  1. button2 = (Button) findViewById(R.id.button2); //获取“用户登录”按钮
  2. button2.setOnClickListener(new OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. Intent intent = new Intent(MainActivity.this,
  6. LoginActivity.class); //创建Intent对象
  7. startActivityForResult(intent, 0x11); //启动新的Activity
  8. }
  9. });

(7)编写LoginActivity,用于实现用户登录。在LoginActivity中,定义程序中所需的成员变量,具体代码如下:

  1. private String username; //保存用户名的变量
  2. private String pwd; //保存密码的变量
  3. private String result = ""; //保存显示结果的变量
  4. private Handler handler; //声明一个Handler对象

(8)编写一个无返回值的login()方法,用于建立一个使用POST请求方式的HTTP连接,并将输入的用户名和密码发送到Web服务器上完成用户登录,然后读取服务器的处理结果,具体代码如下:

  1. public void login() {
  2. String target = "http://192.168.1.66:8081/login/login.jsp"; //要提交的目标地址
  3. HttpPost httpRequest = new HttpPost(target); //创建HttpPost对象
  4. //将要传递的参数保存到List集合中
  5. List<NameValuePair> params = new ArrayList<NameValuePair>();
  6. params.add(new BasicNameValuePair("username", username)); //用户名
  7. params.add(new BasicNameValuePair("pwd", pwd)); //密码
  8. try {
  9. httpRequest.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //设置编码方式
  10. HttpResponse httpResponse = MainActivity.httpclient
  11. .execute(httpRequest); //执行HttpClient请求
  12. if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //如果请求成功
  13. result += EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
  14. } else {
  15. result = "请求失败!";
  16. }
  17. } catch (UnsupportedEncodingException e1) {
  18. e1.printStackTrace(); //输出异常信息
  19. } catch (ClientProtocolException e) {
  20. e.printStackTrace(); //输出异常信息
  21. } catch (IOException e) {
  22. e.printStackTrace(); //输出异常信息
  23. }
  24. }

(9)在LoginActivity的onCreate()方法中,首先设置布局文件,然后获取“登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新线程,用于实现用户登录,最后创建一个Handler对象,并且在重写的handleMessage()方法中获取Intent对象,将result的值作为数据包保存到该Intent对象中,同时返回调用该Activity的MainActivity中。具体代码如下:

  1. setContentView(R.layout.login); //设置布局文件
  2. Button login = (Button) findViewById(R.id.button1); //获取“登录”按钮
  3. login.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. username = ((EditText) findViewById(R.id.editText1)).getText().toString(); //获取输入的用户名
  7. pwd = ((EditText) findViewById(R.id.editText2)).getText().toString(); //获取输入的密码
  8. //创建一个新线程,实现用户登录
  9. new Thread(new Runnable() {
  10. public void run() {
  11. login(); //用户登录
  12. Message m = handler.obtainMessage(); //获取一个Message
  13. handler.sendMessage(m); //发送消息
  14. }
  15. }).start(); //开启线程
  16. }
  17. });
  18. handler = new Handler() {
  19. @Override
  20. public void handleMessage(Message msg) {
  21. if (result != null) {
  22. Intent intent = getIntent(); //获取Intent对象
  23. Bundle bundle = new Bundle(); //实例化传递的数据包
  24. bundle.putString("result", result);
  25. intent.putExtras(bundle); //将数据包保存到intent中
  26. setResult(0x11, intent); //设置返回的结果码,并返回调用该Activity的Main Activity
  27. finish(); //关闭当前Activity
  28. }
  29. super.handleMessage(msg);
  30. }
  31. };

说明:LoginActivity中使用的布局文件的代码与第3章中的例3.6基本相同,这里不再介绍。

(10)获取布局管理器中添加的“退出”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,使用finish()方法关闭当前的Activity。具体代码如下:

  1. Button exit = (Button) findViewById(R.id.button2); //获取“退出”按钮
  2. exit.setOnClickListener(new OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. finish(); //关闭当前Activity
  6. }
  7. });

(11)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

(12)在AndroidManifest.xml文件中配置LoginActivity,配置的主要属性有Activity使用的实现类、标签和主题样式(这里为对话框),具体代码如下:

  1. <activity android:name=".LoginActivity"
  2. android:label="@string/app_name"
  3. android:theme="@android:style/Theme.Dialog"
  4. >
  5. </activity>

另外,还需要编写一个服务器端的Java Web实例。这里需要编写两个页面:一个是index.jsp页面,用于根据Session变量的值来确认当前用户是否有访问页面的权限;另一个是login.jsp页面,用于实现用户登录。

在index.jsp页面中,首先判断Session变量username的值是否为空,如果不为空,则获取Session中保存的用户名,然后判断该用户是否为合法用户,如果是合法用户,则显示公司信息,否则显示提示信息“您没有访问该页面的权限!”。index.jsp文件的具体代码如下:

  1. <%@ page contentType="text/html; charset=utf-8" language="java"%>
  2. <%
  3. String username="";
  4. if(session.getAttribute("username")!=null){
  5. username=session.getAttribute("username").toString(); //获取保存在Session中的用户名
  6. }
  7. if("mr".equals(username)){ //判断是否为合法用户
  8. out.println("吉林省明日科技有限公司");
  9. out.println("Tel:0431-84978981 84978982");
  10. out.println("E-mail:mingrisoft@mingrisoft.com");
  11. out.println("Address:长春市东盛大街89号");
  12. }else{ //没有成功登录时
  13. out.println("您没有访问该页面的权限!");
  14. }
  15. %>

在login.jsp页面中,首先获取参数username(用户名)和pwd(密码)的值,然后判断输入的用户名和密码是否合法,如果合法,则将当前用户名保存到Session中,最后重定向页面到index.jsp页面。login.jsp文件的具体代码如下:

  1. <%@ page contentType="text/html; charset=utf-8" language="java"%>
  2. <%
  3. String username=request.getParameter("username"); //获取用户名
  4. String pwd=request.getParameter("pwd"); //获取密码
  5. if("mr".equals(username)){ //判断用户名是否正确
  6. if("mrsoft".equals(pwd)){ //判断密码是否正确
  7. session.setAttribute("username" , username); //保存用户名到session中
  8. }
  9. }
  10. response.sendRedirect("index.jsp"); //重定向页面到index.jsp页面
  11. %>

将index.jsp和login.jsp文件放到Tomcat安装路径下的webapps\login目录下,并启动Tomcat服务器,然后运行本实例,单击“访问页面”按钮,在下方将显示“您没有访问该页面的权限!”,如图14.7所示;单击“用户登录”按钮,将显示登录对话框,输入用户名(mr)和密码(mrsoft)后,如图14.8所示,单击“登录”按钮,将成功访问指定网页,并显示如图14.9所示的运行结果。

455-1 455-2
图14.7 单击“访问页面”按钮的运行结果 图14.8 单击“用户登录”按钮显示登录对话框

455-3 图14.9 输入正确的用户名和密码后显示公司信息

说明:当用户成功登录后,再次单击“访问页面”按钮,也将显示如图14.9所示的运行结果。这是因为HttpClient会自动维护与服务器之间的Session状态。

14.2 使用WebView显示网页

tb教学录像:光盘\TM\lx\14\使用WebView显示网页.exe

Android提供了内置的浏览器,该浏览器使用了开源的WebKit引擎。WebKit不仅能够搜索网址、查看电子邮件,而且能够播放视频节目。在Android中,要使用内置的浏览器,需要通过WebView组件来实现。通过WebView组件可以轻松实现显示网页功能。下面将对如何使用WebView组件来显示网页进行详细介绍。

14.2.1 使用WebView组件浏览网页

WebView组件是专门用来浏览网页的,其使用方法与其他组件一样,既可以在XML布局文件中使用<WebView>标记添加,又可以在Java文件中通过new关键字创建。推荐采用第一种方法,即通过<WebView>标记在XML布局文件中添加。在XML布局文件中添加一个WebView组件可以使用下面的代码:

  1. <WebView
  2. android:id="@+id/webView1"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" />

添加WebView组件后,就可以应用该组件提供的方法来执行浏览器操作了。Web组件提供的常用方法如表14.2所示。

表14.2 WebView组件提供的常用方法

方 法 描 述
loadUrl(String url) 用于加载指定URL对应的网页
loadData(String data, String mimeType, String encoding) 用于将指定的字符串数据加载到浏览器中
loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) 用于基于URL加载指定的数据
capturePicture() 用于创建当前屏幕的快照
goBack() 执行后退操作,相当于浏览器上的后退按钮的功能
goForward() 执行前进操作,相当于浏览器上的前进按钮的功能
stopLoading() 用于停止加载当前页面
reload() 用于刷新当前页面

下面通过一个具体的实例来说明如何使用WebView组件浏览网页。

例14.7 在Eclipse中创建Android项目,名称为14.7,实现应用WebView组件浏览指定网页。(实例位置:光盘\TM\sl\14\14.7)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个WebView组件,关键代码如下:

  1. <WebView
  2. android:id="@+id/webView1"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" />

(2)在MainActivity的onCreate()方法中,获取布局管理器中添加的WebView组件,并为其指定要加载网页的URL地址,具体代码如下:

  1. WebView webview=(WebView)findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
  2. webview.loadUrl("http://192.168.1.66:8081/bbs/"); //指定要加载的网页

(3)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

运行本实例,在屏幕上将显示通过URL地址指定的网页,如图14.10所示。

457-1 图14.10 使用WebView浏览网页

技巧:如果想让WebView组件具有放大和缩小网页的功能,则要进行以下设置:

  1. webview.getSettings().setSupportZoom(true);
  2. webview.getSettings().setBuiltInZoomControls(true);

14.2.2 使用WebView加载HTML代码

在进行Android开发时,对于一些游戏的帮助信息,使用HTML代码进行显示比较实用,不仅可以让界面更加美观,而且可以让开发更加简单、快捷。WebView组件提供了loadData()和loadDataWithBaseURL()方法来加载HTML代码。使用loadData()方法加载带中文的HTML内容时会产生乱码,但使用loadDataWithBaseURL()方法就不会出现这种情况。loadDataWithBaseURL()方法的基本语法格式如下:

  1. loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)

loadDataWithBaseURL()方法各参数的说明如表14.3所示。

表14.3 loadDataWithBaseURL()方法的参数说明

参 数 描 述
baseUrl 用于指定当前页使用的基本URL。如果为null,则使用默认的about:blank,即空白页
data 用于指定要显示的字符串数据
mimeType 用于指定要显示内容的MIME类型。如果为null,则默认使用text/html
encoding 用于指定数据的编码方式
historyUrl 用于指定当前页的历史URL,也就是进入该页前显示页的URL。如果为null,则使用默认的about:blank

下面通过一个具体的实例来说明如何使用WebView组件加载HTML代码。

例14.8 在Eclipse中创建Android项目,名称为14.8,实现应用WebView组件加载使用HTML代码添加的帮助信息。(实例位置:光盘\TM\sl\14\14.8)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个WebView组件,关键代码如下:

  1. <WebView
  2. android:id="@+id/webView1"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" />

(2)在MainActivity的onCreate()方法中,首先获取布局管理器中添加的WebView组件,然后创建一个字符串构建器,将要显示的HTML代码放置在该构建器中,最后应用loadDataWithBaseURL()方法加载构建器中的HTML代码,具体代码如下:

  1. WebView webview=(WebView)findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
  2. StringBuilder sb=new StringBuilder(); //创建一个字符串构建器,将要显示的HTML内容放置在该构建器中
  3. sb.append("<div>选择选项,然后从以下选项中进行选择:</div>");
  4. sb.append("<ul>");
  5. sb.append("<li>编辑内容:用于增加、移动和删除桌面上的快捷工具。</li>");
  6. sb.append("<li>隐藏内容:用于隐藏桌面上的小工具。</li>");
  7. sb.append("<li>显示内容:用于显示桌面上的小工具。</li>");
  8. sb.append("</ul>");
  9. webview.loadDataWithBaseURL(null, sb.toString(), "text/html", "utf-8", null); //加载数据

运行本实例,在屏幕上将显示如图14.11所示的由HTML代码指定的帮助信息。

458-1 图14.11 使用WebView加载HTML代码

14.2.3 让WebView支持JavaScript

在默认的情况下,WebView组件是不支持JavaScript的,但是在运行某些不得不使用JavaScript代码的网站时,需要让WebView支持JavaScript。实际上,让WebView组件支持JavaScript比较简单,只需以下两个步骤就可以实现。

(1)使用WebView组件的WebSettings对象提供的setJavaScriptEnabled()方法让JavaScript可用。例如,存在一个名称为webview的WebView组件,要设置在该组件中允许使用JavaScript,可以使用下面的代码:

  1. webview.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用

(2)经过以上设置后,网页中的大部分JavaScript代码均可用。但是,对于通过window.alert()方法弹出的对话框并不可用。要想显示弹出的对话框,需要使用WebView组件的setWebChromeClient()方法来处理JavaScript的对话框,具体代码如下:

  1. webview.setWebChromeClient(new WebChromeClient());

这样设置后,在使用WebView显示带弹出JavaScript对话框的网页时,网页中弹出的对话框将不会被屏蔽掉。下面通过一个具体的实例来说明如何让WebView支持JavaScript。

例14.9 在Eclipse中创建Android项目,名称为14.9,实现控制WebView组件是否支持JavaScript。(实例位置:光盘\TM\sl\14\14.9)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个CheckBox和WebView,关键代码如下:

  1. <CheckBox
  2. android:id="@+id/checkBox1"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:text="允许执行JavaScript代码" />
  6. <WebView
  7. android:id="@+id/webView1"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent" />

(2)在MainActivity中,声明一个WebView组件的对象webview,具体代码如下:

  1. private WebView webview; //声明WebView组件的对象

(3)在onCreate()方法中,首先获取布局管理器中添加的WebView组件和复选框组件,然后为复选框组件添加选中状态被改变的事件监听器,在重写的onCheckedChanged()方法中,根据复选框的选中状态决定是否允许使用JavaScript,最后为WebView组件指定要加载的网页,具体代码如下:

  1. webview = (WebView) findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
  2. CheckBox check = (CheckBox) findViewById(R.id.checkBox1); //获取布局管理器中添加的复选框组件
  3. check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
  4. @Override
  5. public void onCheckedChanged(CompoundButton buttonView,
  6. boolean isChecked) {
  7. if (isChecked) {
  8. webview.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
  9. webview.setWebChromeClient(new WebChromeClient());
  10. webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页
  11. }else{
  12. webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页
  13. }
  14. }
  15. });
  16. webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页

(4)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

运行本实例,在屏幕上将显示不支持JavaScript的网页,选中上面的“允许执行JavaScript代码”复选框后,该网页将支持JavaScript。例如,选中“允许执行JavaScript代码”复选框后,单击网页中的“发表”按钮,将弹出一个提示对话框,如图14.12所示。

460-1 图14.12 让WebView支持JavaScript

14.3 经典范例

14.3.1 打造功能实用的网页浏览器

例14.10 在Eclipse中创建Android项目,名称为14.10,实现一个包含前进、后退功能并支持JavaScript的网页浏览器。(实例位置:光盘\TM\sl\14\14.10)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个水平线性布局管理器和一个用于显示网页的WebView组件,并在该布局管理器中添加“前进”按钮、“后退”按钮、地址栏编辑框和GO按钮,具体代码请参见光盘。

(2)在MainActivity中,声明一个WebView组件的对象webView,一个EditText对象和GO按钮对象,具体代码如下:

  1. private WebView webView; //声明WebView组件的对象
  2. private EditText urlText; //声明作为地址栏的EditText对象
  3. private Button goButton; //声明GO按钮对象

(3)在onCreate()方法中,首先获取布局管理器中添加的作为地址栏的EditText组件、GO按钮和WebView组件,然后让WebView组件支持JavaScript,并为WebView组件设置处理各种通知和请求事件,具体代码如下:

  1. urlText=(EditText)findViewById(R.id.editText_url); //获取布局管理器中添加的地址栏
  2. goButton=(Button)findViewById(R.id.button_go); //获取布局管理器中添加的GO按钮
  3. webView=(WebView)findViewById(R.id.webView1); //获取WebView组件
  4. webView.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
  5. webView.setWebChromeClient(new WebChromeClient()); //处理JavaScript对话框
  6. //处理各种通知和请求事件,如果不使用该句代码,将使用内置浏览器访问网页
  7. webView.setWebViewClient(new WebViewClient());

说明:在上面的代码中,加粗的代码一定不能省略,如果不使用该句代码,将使用内置浏览器访问网页。

(4)获取布局管理中添加的“前进”按钮和“后退”按钮,并分别为它们添加单击事件监听器,在“前进”按钮的onClick()方法中调用goForward()方法实现前进功能;在“后退”按钮的onClick()方法中调用goBack()方法实现后退功能。具体代码如下:

  1. Button forward=(Button)findViewById(R.id.forward); //获取布局管理器中添加的“前进”按钮
  2. forward.setOnClickListener(new OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. webView.goForward(); //前进
  6. }
  7. });
  8. Button back=(Button)findViewById(R.id.back); //获取布局管理器中添加的“后退”按钮
  9. back.setOnClickListener(new OnClickListener() {
  10. @Override
  11. public void onClick(View v) {
  12. webView.goBack(); //后退
  13. }
  14. });

(5)为地址栏添加键盘按键被按下的事件监听器,实现当按下键盘上的Enter键时,如果地址栏中的URL地址不为空,则调用openBrowser()方法浏览网页;否则,调用showDialog()方法弹出提示对话框。具体代码如下:

  1. urlText.setOnKeyListener(new OnKeyListener() {
  2. @Override
  3. public boolean onKey(View v, int keyCode, KeyEvent event) {
  4. if(keyCode==KeyEvent.KEYCODE_ENTER){ //如果为Enter键
  5. if(!"".equals(urlText.getText().toString())){
  6. openBrowser(); //浏览网页
  7. return true;
  8. }else{
  9. showDialog(); //弹出提示对话框
  10. }
  11. }
  12. return false;
  13. }
  14. });

(6)为GO按钮添加单击事件监听器,实现单击该按钮时,如果地址栏中的URL地址不为空,则调用openBrowser()方法浏览网页;否则,调用showDialog()方法弹出提示对话框。具体代码如下:

  1. goButton.setOnClickListener(new OnClickListener() {
  2.  
  3. @Override
  4. public void onClick(View v) {
  5. if(!"".equals(urlText.getText().toString())){
  6. openBrowser(); //浏览网页
  7. }else{
  8. showDialog(); //弹出提示对话框
  9. }
  10.  
  11. }
  12. });

(7)编写openBrowser()方法,用于浏览网页,具体代码如下:

  1. private void openBrowser(){
  2. webView.loadUrl(urlText.getText().toString()); //浏览网页
  3. Toast.makeText(this, "正在加载:"+urlText.getText().toString(), Toast.LENGTH_SHORT).show();
  4. }

(8)编写showDialog()方法,用于显示一个带“确定”按钮的对话框,通知用户输入要访问的网址。showDialog()方法的具体代码如下:

  1. private void showDialog(){
  2. new AlertDialog.Builder(MainActivity.this)
  3. .setTitle("网页浏览器")
  4. .setMessage("请输入要访问的网址")
  5. .setPositiveButton("确定",new DialogInterface.OnClickListener(){
  6. public void onClick(DialogInterface dialog,int which){
  7. Log.d("WebWiew","单击确定按钮");
  8. }
  9. }).show();
  10. }

(9)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

运行本实例,单击GO按钮,将访问地址栏中指定的网站,单击“前进”和“后退”按钮,将实现类似于IE浏览器上的前进和后退功能。实例运行结果如图14.13所示。

463-1 图14.13 打造功能实用的网页浏览器

说明:本实例打造的网页浏览器支持JavaScript功能,在图14.13中,输入“评论人”和“评论内容”后,单击“发表”按钮,即可将评论信息显示到上方的评论表格中。

14.3.2 获取天气预报

例14.11 在Eclipse中创建Android项目,名称为14.11,实现获取指定城市的天气预报。(实例位置:光盘\TM\sl\14\14.11)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个水平线性布局管理器和一个用于显示网页的WebView组件,并在该布局管理器中添加“北京”按钮、“上海”按钮、“哈尔滨”按钮、“长春”按钮、“沈阳”按钮和“广州”按钮,具体代码请参见光盘。

(2)在MainActivity中,声明一个WebView组件的对象webView,具体代码如下:

  1. private WebView webView; //声明WebView组件的对象

(3)在onCreate()方法中,首先获取布局管理器中添加的WebView组件,然后设置该组件允许使用JavaScript,并处理JavaScript对话框和各种请求事件,再为WebView组件指定要加载的天气预报信息,最后将网页内容放大4倍,具体代码如下:

  1. webView=(WebView)findViewById(R.id.webView1); //获取WebView组件
  2. webView.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
  3. webView.setWebChromeClient(new WebChromeClient()); //处理JavaScript对话框
  4. //处理各种通知和请求事件,如果不使用该句代码,将使用内置浏览器访问网页
  5. webView.setWebViewClient(new WebViewClient());
  6. webView.loadUrl("http://m.weather.com.cn/m/pn12/weather.htm "); //设置默认显示的天气预报信息
  7. webView.setInitialScale(57*4); //放网页内容放大4倍

(4)让MainActivity实现OnClickListener接口,用于添加单击事件监听器。修改后的代码如下:

  1. public class MainActivity extends Activity implements OnClickListener{

(5)重写onClick()方法,用于为屏幕中的各个按钮的单击事件设置不同的响应,也就是在单击各个按钮时,调用openUrl()方法获取不同地区的天气预报信息,具体代码如下:

  1. @Override
  2. public void onClick(View view){
  3. switch(view.getId()){
  4. case R.id.bj: //单击的是“北京”按钮
  5. openUrl("101010100T");
  6. break;
  7. case R.id.sh: //单击的是“上海”按钮
  8. openUrl("101020100T");
  9. break;
  10. case R.id.heb: //单击的是“哈尔滨”按钮
  11. openUrl("101050101T");
  12. break;
  13. case R.id.cc: //单击的是“长春”按钮
  14. openUrl("101060101T");
  15. break;
  16. case R.id.sy: //单击的是“沈阳”按钮
  17. openUrl("101070101T");
  18. break;
  19. case R.id.gz: //单击的是“广州”按钮
  20. openUrl("101280101T");
  21. break;
  22. }
  23. }

(6)获取布局管理器中添加的“北京”按钮、“上海”按钮、“哈尔滨”按钮、“长春”按钮、“沈阳”按钮和“广州”按钮,并分别为它们添加单击事件监听器,具体代码如下:

  1. Button bj=(Button)findViewById(R.id.bj); //获取布局管理器中添加的“北京”按钮
  2. bj.setOnClickListener(this);
  3. Button sh=(Button)findViewById(R.id.sh); //获取布局管理器中添加的“上海”按钮
  4. sh.setOnClickListener(this);
  5. Button heb=(Button)findViewById(R.id.heb); //获取布局管理器中添加的“哈尔滨”按钮
  6. heb.setOnClickListener(this);
  7. Button cc=(Button)findViewById(R.id.cc); //获取布局管理器中添加的“长春”按钮
  8. cc.setOnClickListener(this);
  9. Button sy=(Button)findViewById(R.id.sy); //获取布局管理器中添加的“沈阳”按钮
  10. sy.setOnClickListener(this);
  11. Button gz=(Button)findViewById(R.id.gz); //获取布局管理器中添加的“广州”按钮
  12. gz.setOnClickListener(this);

(7)编写用于打开网页获取天气预报信息的方法openUrl(),在该方法中,将根据传递的参数不同,获取不同地区的天气预报信息,具体代码如下:

  1. private void openUrl(String id){
  2. webView.loadUrl("http://m.weather.com.cn/m/pn12/weather.htm?id="+id+" "); //获取并显示天气预报信息
  3. }

说明:在中国天气网(http://www.weather.com.cn/)中提供了单城市24小时天气预报插件,使用该插件可以实现在Android中获取指定城市的天气预报。

(8)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:

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

运行本实例,在屏幕上将显示默认城市的天气预报信息,单击上方的“北京”、“上海”、“哈尔滨”、“长春”、“沈阳”和“广州”按钮,将显示对应城市的天气预报信息。例如,单击“长春”按钮,将显示如图14.14所示的效果。

465-1 图14.14 获取长春市的天气预报

14.4 小 结

本章首先介绍了如何通过HTTP访问网络,主要有两种方法:一种是使用java.net包中的HttpURLConnection实现;另一种是通过Android提供的HttpClient实现。对于一些简单的访问网络的操作,可以使用HttpURLConnection实现,但是如果操作比较复杂,就需要使用HttpClient来实现了。之后介绍了使用Android提供的WebView组件来显示网页,使用该组件可以很方便地实现基本的网页浏览器功能。

14.5 实践与练习

  1. 编写Android项目,在发送GET请求时,不使用Base64编码来解决中文乱码问题。(答案位置:光盘\TM\sl\14\14.12)

  2. 编写Android项目,实现使用系统内置的浏览器打开指定网页。(答案位置:光盘\TM\sl\14\14.13)