第14章 网络编程及Internet应用
(教学录像:1小时36分钟)
Google公司以网络搜索引擎起家,通过大胆的创意和不断的研发努力,目前已经成为网络世界的巨头,而出自于Google之手的Android平台,在网络编程和Internet应用上也是非常优秀的。本章将对Android中的网络编程和Internet应用的相关知识进行详细介绍。
通过阅读本章,您可以:
★ 掌握使用HttpURLConnection访问网络的方法
★ 掌握使用HttpClient访问网络的方法
★ 掌握如何使用WebView组件浏览网页
★ 掌握在WebView组件中加载HTML代码的方法
★ 掌握让WebView组件支持JavaScript的方法
14.1 通过HTTP访问网络
教学录像:光盘\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对象,可以使用下面的代码:
- URL url = new URL("http://www.mingribook.com/");
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
说明:通过openConnection()方法创建的HttpURLConnection对象,并没有真正执行连接操作,只是创建了一个新的实例,在进行连接前,还可以设置一些属性。例如,连接超时的时间和请求方式等。
创建了HttpURLConnection对象后,就可以使用该对象发送HTTP请求了。HTTP请求通常分为GET请求和POST请求两种,下面分别进行介绍。
- 发送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的编辑框(用于输入微博内容)以及一个“发表”按钮,再添加一个滚动视图,并在该视图中添加一个线性布局管理器,最后还需要在该线性布局管理器中添加一个文本框,用于显示从服务器上读取的微博内容,关键代码如下:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
- <EditText
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <Button
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button" />
- <ScrollView
- android:id="@+id/scrollView1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
- <LinearLayout
- android:id="@+id/linearLayout1"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <TextView
- android:id="@+id/result"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1" />
- </LinearLayout>
- </ScrollView>
- </LinearLayout>
(2)在该MainActivity中,创建程序中所需的成员变量,具体代码如下:
- private EditText content; //声明一个输入文本内容的编辑框对象
- private Button button; //声明一个“发表”按钮对象
- private Handler handler; //声明一个Handler对象
- private String result = ""; //声明一个代表显示内容的字符串
- private TextView resultTV; //声明一个显示结果的文本框对象
(3)编写一个无返回值的send()方法,用于建立一个HTTP连接,并将输入的内容发送到Web服务器上,再读取服务器的处理结果,具体代码如下:
- public void send() {
- String target="";
- target = "http://192.168.1.66:8081/blog/index.jsp?content="
- +base64(content.getText().toString().trim()); //要访问的URL地址
- URL url;
- try {
- url = new URL(target); //创建URL对象
- HttpURLConnection urlConn = (HttpURLConnection) url
- .openConnection(); //创建一个HTTP连接
- InputStreamReader in = new InputStreamReader(
- urlConn.getInputStream()); //获得读取的内容
- BufferedReader buffer = new BufferedReader(in); //获取输入流对象
- String inputLine = null;
- //通过循环逐行读取输入流中的内容
- while ((inputLine = buffer.readLine()) != null) {
- result += inputLine + "\n";
- }
- in.close(); //关闭字符输入流对象
- urlConn.disconnect(); //断开连接
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
(4)在应用GET方法传递中文的参数时,会产生乱码,这时可以进行Base64编码来解决乱码问题,为此,需要编写一个base64()方法,对要进行传递的参数进行Base64编码。base64()方法的具体代码如下:
- public String base64(String content){
- try {
- //对字符串进行Base64编码
- content=Base64.encodeToString(content.getBytes("utf-8"), Base64.DEFAULT);
- content=URLEncoder.encode(content); //对字符串进行URL编码
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace(); //输出异常信息
- }
- return content;
- }
说明:要解决应用GET方法传递中文参数时产生乱码的问题,也可以使用Java提供的URLEncoder类来实现。
(5)在onCreate()方法中,获取布局管理器中用于输入内容的编辑框、用于显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的内容是否为空,如果为空,则给出消息提示;否则,创建一个新的线程,调用send()方法发送并读取微博信息,具体代码如下:
- content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
- resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
- button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
- //为按钮添加单击事件监听器
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if ("".equals(content.getText().toString())) {
- Toast.makeText(MainActivity.this, "请输入要发表的内容!",
- Toast.LENGTH_SHORT).show(); //显示消息提示
- return;
- }
- //创建一个新线程,用于发送并读取微博信息
- new Thread(new Runnable() {
- public void run() {
- send(); //发送文本内容到Web服务器,并读取
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(6)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空编辑器,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- resultTV.setText(result); //显示获得的结果
- content.setText(""); //清空编辑框
- }
- super.handleMessage(msg);
- }
- };
(7)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为index.jsp的文件,在该文件中,首先获取参数content指定的微博信息,并保存到变量content中,然后替换变量content中的加号,这是由于在进行URL编码时,将加号转换为了%2B,最后对content进行Base64解码,并输出转码后的content变量的值,具体代码如下:
- <%@ page contentType="text/html; charset=utf-8" language="java" import="sun.misc.BASE64Decoder"%>
- <%
- String content="";
- if(request.getParameter("content")!=null){
- content=request.getParameter("content"); //获取输入的微博信息
- //替换content中的加号,这是由于在进行URL编码时,将"+"号转换为了%2B
- content=content.replaceAll("%2B","+");
- BASE64Decoder decoder=new BASE64Decoder();
- content=new String(decoder.decodeBuffer(content),"utf-8"); //进行Base64解码
- }
- %>
- <%="发表一条微博,内容如下:"%>
- <%=content%>
将index.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入一条微博信息,再单击“发表”按钮,在下方将显示Web服务器的处理结果。例如,输入“坚持到底就是胜利!”后,单击“发表”按钮,将显示如图14.1所示的运行结果。
图14.1 使用GET方式发表并显示微博信息
- 发送POST请求
由于采用GET方式发送请求只适合发送大小在1024个字节以内的数据,所以当要发送的数据较大时,就需要使用POST方式来发送请求。在Android中,使用HttpURLConnection类发送请求时,默认采用的是GET请求,如果要发送POST请求,需要通过其setRequestMethod()方法进行指定。例如,创建一个HTTP连接,并为该连接指定请求的发送方式为POST,可以使用下面的代码:
- HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); //创建一个HTTP连接
- 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中,创建程序中所需的成员变量,具体代码如下:
- private EditText nickname; //声明一个输入昵称的编辑框对象
- private EditText content; //声明一个输入文本内容的编辑框对象
- private Button button; //声明一个"发表"按钮对象
- private Handler handler; //声明一个Handler对象
- private String result = ""; //声明一个代表显示内容的字符串
- private TextView resultTV; //声明一个显示结果的文本框对象
(3)编写一个无返回值的send()方法,用于建立一个HTTP连接,并使用POST方式将输入的昵称和内容发送到Web服务器上,再读取服务器处理的结果,具体代码如下:
- public void send() {
- String target = "http://192.168.1.66:8081/blog/dealPost.jsp"; //要提交的目标地址
- URL url;
- try {
- url = new URL(target);
- HttpURLConnection urlConn = (HttpURLConnection) url
- .openConnection(); //创建一个HTTP连接
- urlConn.setRequestMethod("POST"); //指定使用POST请求方式
- urlConn.setDoInput(true); //向连接中写入数据
- urlConn.setDoOutput(true); //从连接中读取数据
- urlConn.setUseCaches(false); //禁止缓存
- urlConn.setInstanceFollowRedirects(true); //自动执行HTTP重定向
- urlConn.setRequestProperty("Content-Type",
- "application/x-www-form-urlencoded"); //设置内容类型
- DataOutputStream out = new DataOutputStream(
- urlConn.getOutputStream()); //获取输出流
- String param = "nickname="
- + URLEncoder.encode(nickname.getText().toString(), "utf-8")
- + "&content="
- + URLEncoder.encode(content.getText().toString(), "utf-8"); //连接要提交的数据
- out.writeBytes(param); //将要传递的数据写入数据输出流
- out.flush(); //输出缓存
- out.close(); //关闭数据输出流
- //判断是否响应成功
- if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
- InputStreamReader in = new InputStreamReader(
- urlConn.getInputStream()); //获得读取的内容
- BufferedReader buffer = new BufferedReader(in); //获取输入流对象
- String inputLine = null;
- while ((inputLine = buffer.readLine()) != null) {
- result += inputLine + "\n";
- }
- in.close(); //关闭字符输入流
- }
- urlConn.disconnect(); //断开连接
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
说明:在设置要提交的数据时,如果包括多个参数,则各个参数间使用“&”进行连接。
(4)在onCreate()方法中,获取布局管理器中添加的昵称编辑框、内容编辑框、显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的昵称和内容是否为空,只要有一个为空,就给出消息提示;否则,创建一个新的线程,用于调用send()方法发送并读取服务器处理后的微博信息,具体代码如下:
- content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
- resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
- nickname=(EditText)findViewById(R.id.nickname); //获取输入昵称的EditText组件
- button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
- //为按钮添加单击事件监听器
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if ("".equals(content.getText().toString())) {
- Toast.makeText(MainActivity.this, "请输入要发表的内容!",Toast.LENGTH_SHORT).show();
- return;
- }
- //创建一个新线程,用于发送并读取微博信息
- new Thread(new Runnable() {
- public void run() {
- send();
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空昵称和内容编辑器,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- resultTV.setText(result); //显示获得的结果
- content.setText(""); //清空内容编辑框
- nickname.setText(""); //清空昵称编辑框
- }
- super.handleMessage(msg);
- }
- };
(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为dealPost.jsp的文件,在该文件中,首先获取参数nickname和content指定的昵称和微博信息,并保存到相应的变量中,然后当昵称和微博内容均不为空时,对其进行转码,并获取系统时间,同时组合微博信息输出到页面上,具体代码如下:
- <%@ page contentType="text/html; charset=utf-8" language="java" %>
- <%
- String content=request.getParameter("content"); //获取输入的微博信息
- String nickname=request.getParameter("nickname"); //获取输入的昵称
- if(content!=null && nickname!=null){
- nickname=new String(nickname.getBytes("iso-8859-1"),"utf-8"); //对昵称进行转码
- content=new String(content.getBytes("iso-8859-1"),"utf-8"); //对内容进行转码
- String date=new java.util.Date().toLocaleString(); //获取系统时间
- %>
- <%="[ "+nickname+" ]于 "+date+" 发表一条微博,内容如下:"%>
- <%=content%>
- <% }%>
将dealPost.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入昵称和微博信息,单击“发表”按钮,在下方将显示Web服务器的处理结果。例如,输入昵称为“无语”、微博内容为“坚持到底就是胜利!”后,单击“发表”按钮,将显示如图14.2所示的运行结果。
图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请求两种,下面分别进行介绍。
- 发送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中,创建程序中所需的成员变量,具体代码如下:
- private Button button; //声明一个“发送GET请求”按钮对象
- private Handler handler; //声明一个Handler对象
- private String result = ""; //声明一个代表显示结果的字符串
- private TextView resultTV; //声明一个显示结果的文本框对象
(3)编写一个无返回值的send()方法,用于建立一个发送GET请求的HTTP连接,并将指定的参数发送到Web服务器上,再读取服务器的响应信息,具体代码如下:
- public void send() {
- String target = "http://192.168.1.66:8081/blog/deal_httpclient.jsp?param=get"; //要提交的目标地址
- HttpClient httpclient = new DefaultHttpClient(); //创建HttpClient对象
- HttpGet httpRequest = new HttpGet(target); //创建HttpGet连接对象
- HttpResponse httpResponse;
- try {
- httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
- result = EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
- }else{
- result="请求失败!";
- }
- } catch (ClientProtocolException e) {
- e.printStackTrace(); //输出异常信息
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
(4)在onCreate()方法中,获取布局管理器中添加的用于显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新的线程,并且在重写的run()方法中,首先调用send()方法发送并读取微博信息,然后获取一个Message对象,并调用其sendMessage()方法发送消息,具体代码如下:
- resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
- button = (Button) findViewById(R.id.button); //获取“发送GET请求”按钮组件
- //为按钮添加单击事件监听器
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //创建一个新线程,用于发送并获取GET请求
- new Thread(new Runnable() {
- public void run() {
- send();
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- resultTV.setText(result); //显示获得的结果
- }
- super.handleMessage(msg);
- }
- };
(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里编写一个名称为deal_httpclient.jsp的文件,在该文件中,首先获取参数param的值,如果该值不为空,则判断其值是否为get,如果是get,则输出文字“发送GET请求成功!”,具体代码如下:
- <%@ page contentType="text/html; charset=utf-8" language="java" %>
- <%
- String param=request.getParameter("param"); //获取参数值
- if(!"".equals(param) || param!=null){
- if("get".equals(param)){
- out.println("发送GET请求成功!");
- }
- }
- %>
将deal_httpclient.jsp文件放到Tomcat安装路径下的webapps\blog目录下,并启动Tomcat服务器,然后运行本实例,单击“发送GET请求”按钮,在下方将显示Web服务器的处理结果。如果请求发送成功,则显示如图14.3所示的运行结果;否则,显示文字“请求失败!”。
图14.3 应用HttpClient发送GET请求
- 发送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中,创建程序中所需的成员变量,具体代码如下:
- private EditText nickname; //声明一个输入昵称的编辑框对象
- private EditText content; //声明一个输入文本内容的编辑框对象
- private Button button; //声明一个“发表”按钮对象
- private Handler handler; //声明一个Handler对象
- private String result = ""; //声明一个代表显示内容的字符串
- private TextView resultTV; //声明一个显示结果的文本框对象
(3)编写一个无返回值的send()方法,用于建立一个使用POST请求方式的HTTP连接,并将输入的昵称和微博内容发送到Web服务器上,再读取服务器处理的结果,具体代码如下:
- public void send() {
- String target = "http://192.168.1.66:8081/blog/deal_httpclient.jsp"; //要提交的目标地址
- HttpClient httpclient = new DefaultHttpClient(); //创建HttpClient对象
- HttpPost httpRequest = new HttpPost(target); //创建HttpPost对象
- //将要传递的参数保存到List集合中
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("param", "post")); //标记参数
- params.add(new BasicNameValuePair("nickname", nickname.getText().toString())); //昵称
- params.add(new BasicNameValuePair("content", content.getText().toString())); //内容
- try {
- httpRequest.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //设置编码方式
- HttpResponse httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ //如果请求成功
- result += EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
- }else{
- result = "请求失败!";
- }
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace(); //输出异常信息
- } catch (ClientProtocolException e) {
- e.printStackTrace(); //输出异常信息
- } catch (IOException e) {
- e.printStackTrace(); //输出异常信息
- }
- }
(4)在onCreate()方法中,获取布局管理器中添加的昵称编辑框、内容编辑框、显示结果的文本框和“发表”按钮,并为“发表”按钮添加单击事件监听器,在重写的onClick()方法中,首先判断输入的昵称和内容是否为空,只要有一个为空,就给出消息提示;否则,创建一个新的线程,调用send()方法发送并读取服务器处理后的微博信息,具体代码如下:
- content = (EditText) findViewById(R.id.content); //获取输入文本内容的EditText组件
- resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
- nickname=(EditText)findViewById(R.id.nickname); //获取输入昵称的EditText组件
- button = (Button) findViewById(R.id.button); //获取“发表”按钮组件
- //为按钮添加单击事件监听器
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if ("".equals(content.getText().toString())) {
- Toast.makeText(MainActivity.this, "请输入要发表的内容!",Toast.LENGTH_SHORT).show();
- return;
- }
- //创建一个新线程,用于发送并读取微博信息
- new Thread(new Runnable() {
- public void run() {
- send();
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,并清空昵称和内容编辑器,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- resultTV.setText(result); //显示获得的结果
- content.setText(""); //清空内容编辑框
- nickname.setText(""); //清空昵称编辑框
- }
- super.handleMessage(msg);
- }
- };
(6)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
另外,还需要编写一个Java Web实例,用于接收Android客户端发送的请求,并做出响应。这里仍然使用例14.3中创建的deal_httpclient.jsp文件,在该文件的if语句的结尾处添加一个else if语句,用于处理当请求参数param的值为post的情况。关键代码如下:
- else if("post".equals(param)){
- String content=request.getParameter("content"); //获取输入的微博信息
- String nickname=request.getParameter("nickname"); //获取输入昵称
- if(content!=null && nickname!=null){
- nickname=new String(nickname.getBytes("iso-8859-1"),"utf-8"); //对昵称进行转码
- content=new String(content.getBytes("iso-8859-1"),"utf-8"); //对内容进行转码
- String date=new java.util.Date().toLocaleString(); //获取系统时间
- out.println("[ "+nickname+" ]于 "+date+" 发表一条微博,内容如下:");
- out.println(content);
- }
- }
说明:在上面的代码中,首先获取参数nickname和content指定的昵称和微博信息,并保存到相应的变量中,然后当昵称和微博内容均不为空时对其进行转码,并获取系统时间,同时组合微博信息输出到页面上。
将deal_httpclient.jsp文件放到Tomcat安装路径下的webapps/blog目录下,并启动Tomcat服务器,然后运行本实例,在屏幕上方的编辑框中输入昵称和微博信息,单击“发表”按钮,在下方将显示Web服务器的处理结果。实例运行结果如图14.4所示。
图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中,创建程序中所需的成员变量,具体代码如下:
- private EditText urlText; //下载地址编辑框
- private Button button; //下载按钮
- private Handler handler; //声明一个Handler对象
- private boolean flag = false; //标记是否成功的变量
(3)在onCreate()方法中,获取布局管理器中添加的下载地址编辑框和“下载”按钮,并为“下载”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新线程,用于从网络上获取文件;在重写的run()方法中,首先获取文件的下载地址,并创建一个相关的连接,然后获取输入流对象,并从下载地址中获取要下载文件的文件名及扩展名,再读取文件到一个输出流对象中,并关闭相关对象及断开连接,最后获取一个Message并发送消息,具体代码如下:
- urlText = (EditText) findViewById(R.id.editText_url); //获取布局管理器中添加的下载地址编辑框
- button = (Button) findViewById(R.id.button_go); //获取布局管理器中添加的“下载”按钮
- //为“下载”按钮添加单击事件监听器
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //创建一个新线程,用于从网络上获取文件
- new Thread(new Runnable() {
- public void run() {
- try {
- String sourceUrl = urlText.getText().toString(); //获取下载地址
- URL url = new URL(sourceUrl); //创建下载地址对应的URL对象
- HttpURLConnection urlConn = (HttpURLConnection) url
- .openConnection(); //创建一个连接
- InputStream is = urlConn.getInputStream(); //获取输入流对象
- if (is != null) {
- String expandName = sourceUrl.substring(
- sourceUrl.lastIndexOf(".") + 1,
- sourceUrl.length()).toLowerCase(); //获取文件的扩展名
- String fileName = sourceUrl.substring(
- sourceUrl.lastIndexOf("/") + 1,
- sourceUrl.lastIndexOf(".")); //获取文件名
- File file = new File("/sdcard/pictures/"
- + fileName + "." + expandName); //在SD卡上创建文件
- FileOutputStream fos = new FileOutputStream(
- file); //创建一个文件输出流对象
- byte buf[] = new byte[128]; //创建一个字节数组
- //读取文件到输出流对象中
- while (true) {
- int numread = is.read(buf);
- if (numread <= 0) {
- break;
- } else {
- fos.write(buf, 0, numread);
- }
- }
- }
- is.close(); //关闭输入流对象
- urlConn.disconnect(); //关闭连接
- flag = true;
- } catch (MalformedURLException e) {
- e.printStackTrace(); //输出异常信息
- flag = false;
- } catch (IOException e) {
- e.printStackTrace(); //输出异常信息
- flag = false;
- }
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(4)创建一个Handler对象,在重写的handleMessage()方法中,根据标记变量flag的值显示不同的消息提示,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (flag) {
- Toast.makeText(MainActivity.this, "文件下载完成!",
- Toast.LENGTH_SHORT).show(); //显示消息提示
- } else {
- Toast.makeText(MainActivity.this, "文件下载失败!",
- Toast.LENGTH_SHORT).show(); //显示消息提示
- }
- super.handleMessage(msg);
- }
- };
(5)由于在本实例中需要访问网络资源并向SD卡上写文件,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源和向SD卡上写文件的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
运行本实例,在下载地址编辑框中输入要下载文件的URL地址,单击“下载”按钮,即可将指定的文件下载到SD卡上。成功的前提是指定的URL地址真实存在,并且相应的文件也存在。实例运行结果如图14.5和图14.6所示。
图14.5 从指定网站下载文件
图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中,创建程序中所需的成员变量,具体代码如下:
- private Button button1; //声明一个“访问页面”按钮对象
- private Button button2; //声明一个“用户登录”按钮对象
- private Handler handler; //声明一个Handler对象
- private String result = ""; //声明一个代表显示内容的字符串
- private TextView resultTV; //声明一个显示结果的文本框对象
- public static HttpClient httpclient; //声明一个静态的全局HttpClient对象
(3)编写一个无返回值的access()方法,用于建立一个发送GET请求的HTTP连接,并从服务器获得响应信息,具体代码如下:
- public void access() {
- String target = "http://192.168.1.66:8081/login/index.jsp"; //要提交的目标地址
- HttpGet httpRequest = new HttpGet(target); //创建HttpGet对象
- HttpResponse httpResponse;
- try {
- httpResponse = httpclient.execute(httpRequest); //执行HttpClient请求
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- result = EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
- } else {
- result = "请求失败!";
- }
- } catch (ClientProtocolException e) {
- e.printStackTrace(); //输出异常信息
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
(4)在onCreate()方法中,创建一个HttpClient对象,并获取显示结果的TextView组件和“访问页面”按钮,同时为“访问页面”按钮添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新的线程,在重写的run()方法中,首先调用access()方法向服务器发送一个GET请求,并获取响应结果,然后获取一个Message对象,并调用其sendMessage()方法发送消息,具体代码如下:
- httpclient = new DefaultHttpClient(); //创建HttpClient对象
- resultTV = (TextView) findViewById(R.id.result); //获取显示结果的TextView组件
- button1 = (Button) findViewById(R.id.button1); //获取“访问页面”按钮组件
- //为按钮添加单击事件监听器
- button1.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //创建一个新线程,用于向服务器发送一个GET请求
- new Thread(new Runnable() {
- public void run() {
- access();
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
(5)创建一个Handler对象,在重写的handleMessage()方法中,当变量result不为空时,将其显示到结果文本框中,具体代码如下:
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- resultTV.setText(result); //显示获得的结果
- }
- super.handleMessage(msg);
- }
- };
(6)获取布局管理器中添加的“用户登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建一个Intent对象,并启动一个新的带返回结果的Activity,具体代码如下:
- button2 = (Button) findViewById(R.id.button2); //获取“用户登录”按钮
- button2.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(MainActivity.this,
- LoginActivity.class); //创建Intent对象
- startActivityForResult(intent, 0x11); //启动新的Activity
- }
- });
(7)编写LoginActivity,用于实现用户登录。在LoginActivity中,定义程序中所需的成员变量,具体代码如下:
- private String username; //保存用户名的变量
- private String pwd; //保存密码的变量
- private String result = ""; //保存显示结果的变量
- private Handler handler; //声明一个Handler对象
(8)编写一个无返回值的login()方法,用于建立一个使用POST请求方式的HTTP连接,并将输入的用户名和密码发送到Web服务器上完成用户登录,然后读取服务器的处理结果,具体代码如下:
- public void login() {
- String target = "http://192.168.1.66:8081/login/login.jsp"; //要提交的目标地址
- HttpPost httpRequest = new HttpPost(target); //创建HttpPost对象
- //将要传递的参数保存到List集合中
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("username", username)); //用户名
- params.add(new BasicNameValuePair("pwd", pwd)); //密码
- try {
- httpRequest.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //设置编码方式
- HttpResponse httpResponse = MainActivity.httpclient
- .execute(httpRequest); //执行HttpClient请求
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //如果请求成功
- result += EntityUtils.toString(httpResponse.getEntity()); //获取返回的字符串
- } else {
- result = "请求失败!";
- }
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace(); //输出异常信息
- } catch (ClientProtocolException e) {
- e.printStackTrace(); //输出异常信息
- } catch (IOException e) {
- e.printStackTrace(); //输出异常信息
- }
- }
(9)在LoginActivity的onCreate()方法中,首先设置布局文件,然后获取“登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建并开启一个新线程,用于实现用户登录,最后创建一个Handler对象,并且在重写的handleMessage()方法中获取Intent对象,将result的值作为数据包保存到该Intent对象中,同时返回调用该Activity的MainActivity中。具体代码如下:
- setContentView(R.layout.login); //设置布局文件
- Button login = (Button) findViewById(R.id.button1); //获取“登录”按钮
- login.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- username = ((EditText) findViewById(R.id.editText1)).getText().toString(); //获取输入的用户名
- pwd = ((EditText) findViewById(R.id.editText2)).getText().toString(); //获取输入的密码
- //创建一个新线程,实现用户登录
- new Thread(new Runnable() {
- public void run() {
- login(); //用户登录
- Message m = handler.obtainMessage(); //获取一个Message
- handler.sendMessage(m); //发送消息
- }
- }).start(); //开启线程
- }
- });
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (result != null) {
- Intent intent = getIntent(); //获取Intent对象
- Bundle bundle = new Bundle(); //实例化传递的数据包
- bundle.putString("result", result);
- intent.putExtras(bundle); //将数据包保存到intent中
- setResult(0x11, intent); //设置返回的结果码,并返回调用该Activity的Main Activity
- finish(); //关闭当前Activity
- }
- super.handleMessage(msg);
- }
- };
说明:LoginActivity中使用的布局文件的代码与第3章中的例3.6基本相同,这里不再介绍。
(10)获取布局管理器中添加的“退出”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,使用finish()方法关闭当前的Activity。具体代码如下:
- Button exit = (Button) findViewById(R.id.button2); //获取“退出”按钮
- exit.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); //关闭当前Activity
- }
- });
(11)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
(12)在AndroidManifest.xml文件中配置LoginActivity,配置的主要属性有Activity使用的实现类、标签和主题样式(这里为对话框),具体代码如下:
- <activity android:name=".LoginActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Dialog"
- >
- </activity>
另外,还需要编写一个服务器端的Java Web实例。这里需要编写两个页面:一个是index.jsp页面,用于根据Session变量的值来确认当前用户是否有访问页面的权限;另一个是login.jsp页面,用于实现用户登录。
在index.jsp页面中,首先判断Session变量username的值是否为空,如果不为空,则获取Session中保存的用户名,然后判断该用户是否为合法用户,如果是合法用户,则显示公司信息,否则显示提示信息“您没有访问该页面的权限!”。index.jsp文件的具体代码如下:
- <%@ page contentType="text/html; charset=utf-8" language="java"%>
- <%
- String username="";
- if(session.getAttribute("username")!=null){
- username=session.getAttribute("username").toString(); //获取保存在Session中的用户名
- }
- if("mr".equals(username)){ //判断是否为合法用户
- out.println("吉林省明日科技有限公司");
- out.println("Tel:0431-84978981 84978982");
- out.println("E-mail:mingrisoft@mingrisoft.com");
- out.println("Address:长春市东盛大街89号");
- }else{ //没有成功登录时
- out.println("您没有访问该页面的权限!");
- }
- %>
在login.jsp页面中,首先获取参数username(用户名)和pwd(密码)的值,然后判断输入的用户名和密码是否合法,如果合法,则将当前用户名保存到Session中,最后重定向页面到index.jsp页面。login.jsp文件的具体代码如下:
- <%@ page contentType="text/html; charset=utf-8" language="java"%>
- <%
- String username=request.getParameter("username"); //获取用户名
- String pwd=request.getParameter("pwd"); //获取密码
- if("mr".equals(username)){ //判断用户名是否正确
- if("mrsoft".equals(pwd)){ //判断密码是否正确
- session.setAttribute("username" , username); //保存用户名到session中
- }
- }
- response.sendRedirect("index.jsp"); //重定向页面到index.jsp页面
- %>
将index.jsp和login.jsp文件放到Tomcat安装路径下的webapps\login目录下,并启动Tomcat服务器,然后运行本实例,单击“访问页面”按钮,在下方将显示“您没有访问该页面的权限!”,如图14.7所示;单击“用户登录”按钮,将显示登录对话框,输入用户名(mr)和密码(mrsoft)后,如图14.8所示,单击“登录”按钮,将成功访问指定网页,并显示如图14.9所示的运行结果。
![]() | ![]() |
图14.7 单击“访问页面”按钮的运行结果 | 图14.8 单击“用户登录”按钮显示登录对话框 |
图14.9 输入正确的用户名和密码后显示公司信息
说明:当用户成功登录后,再次单击“访问页面”按钮,也将显示如图14.9所示的运行结果。这是因为HttpClient会自动维护与服务器之间的Session状态。
14.2 使用WebView显示网页
教学录像:光盘\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组件可以使用下面的代码:
- <WebView
- android:id="@+id/webView1"
- android:layout_width="match_parent"
- 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组件,关键代码如下:
- <WebView
- android:id="@+id/webView1"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
(2)在MainActivity的onCreate()方法中,获取布局管理器中添加的WebView组件,并为其指定要加载网页的URL地址,具体代码如下:
- WebView webview=(WebView)findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
- webview.loadUrl("http://192.168.1.66:8081/bbs/"); //指定要加载的网页
(3)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
运行本实例,在屏幕上将显示通过URL地址指定的网页,如图14.10所示。
图14.10 使用WebView浏览网页
技巧:如果想让WebView组件具有放大和缩小网页的功能,则要进行以下设置:
- webview.getSettings().setSupportZoom(true);
- webview.getSettings().setBuiltInZoomControls(true);
14.2.2 使用WebView加载HTML代码
在进行Android开发时,对于一些游戏的帮助信息,使用HTML代码进行显示比较实用,不仅可以让界面更加美观,而且可以让开发更加简单、快捷。WebView组件提供了loadData()和loadDataWithBaseURL()方法来加载HTML代码。使用loadData()方法加载带中文的HTML内容时会产生乱码,但使用loadDataWithBaseURL()方法就不会出现这种情况。loadDataWithBaseURL()方法的基本语法格式如下:
- 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组件,关键代码如下:
- <WebView
- android:id="@+id/webView1"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
(2)在MainActivity的onCreate()方法中,首先获取布局管理器中添加的WebView组件,然后创建一个字符串构建器,将要显示的HTML代码放置在该构建器中,最后应用loadDataWithBaseURL()方法加载构建器中的HTML代码,具体代码如下:
- WebView webview=(WebView)findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
- StringBuilder sb=new StringBuilder(); //创建一个字符串构建器,将要显示的HTML内容放置在该构建器中
- sb.append("<div>选择选项,然后从以下选项中进行选择:</div>");
- sb.append("<ul>");
- sb.append("<li>编辑内容:用于增加、移动和删除桌面上的快捷工具。</li>");
- sb.append("<li>隐藏内容:用于隐藏桌面上的小工具。</li>");
- sb.append("<li>显示内容:用于显示桌面上的小工具。</li>");
- sb.append("</ul>");
- webview.loadDataWithBaseURL(null, sb.toString(), "text/html", "utf-8", null); //加载数据
运行本实例,在屏幕上将显示如图14.11所示的由HTML代码指定的帮助信息。
图14.11 使用WebView加载HTML代码
14.2.3 让WebView支持JavaScript
在默认的情况下,WebView组件是不支持JavaScript的,但是在运行某些不得不使用JavaScript代码的网站时,需要让WebView支持JavaScript。实际上,让WebView组件支持JavaScript比较简单,只需以下两个步骤就可以实现。
(1)使用WebView组件的WebSettings对象提供的setJavaScriptEnabled()方法让JavaScript可用。例如,存在一个名称为webview的WebView组件,要设置在该组件中允许使用JavaScript,可以使用下面的代码:
- webview.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
(2)经过以上设置后,网页中的大部分JavaScript代码均可用。但是,对于通过window.alert()方法弹出的对话框并不可用。要想显示弹出的对话框,需要使用WebView组件的setWebChromeClient()方法来处理JavaScript的对话框,具体代码如下:
- 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,关键代码如下:
- <CheckBox
- android:id="@+id/checkBox1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="允许执行JavaScript代码" />
- <WebView
- android:id="@+id/webView1"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
(2)在MainActivity中,声明一个WebView组件的对象webview,具体代码如下:
- private WebView webview; //声明WebView组件的对象
(3)在onCreate()方法中,首先获取布局管理器中添加的WebView组件和复选框组件,然后为复选框组件添加选中状态被改变的事件监听器,在重写的onCheckedChanged()方法中,根据复选框的选中状态决定是否允许使用JavaScript,最后为WebView组件指定要加载的网页,具体代码如下:
- webview = (WebView) findViewById(R.id.webView1); //获取布局管理器中添加的WebView组件
- CheckBox check = (CheckBox) findViewById(R.id.checkBox1); //获取布局管理器中添加的复选框组件
- check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView,
- boolean isChecked) {
- if (isChecked) {
- webview.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
- webview.setWebChromeClient(new WebChromeClient());
- webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页
- }else{
- webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页
- }
- }
- });
- webview.loadUrl("http://192.168.1.66:8081/bbs/allowJS.jsp"); //指定要加载的网页
(4)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
运行本实例,在屏幕上将显示不支持JavaScript的网页,选中上面的“允许执行JavaScript代码”复选框后,该网页将支持JavaScript。例如,选中“允许执行JavaScript代码”复选框后,单击网页中的“发表”按钮,将弹出一个提示对话框,如图14.12所示。
图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按钮对象,具体代码如下:
- private WebView webView; //声明WebView组件的对象
- private EditText urlText; //声明作为地址栏的EditText对象
- private Button goButton; //声明GO按钮对象
(3)在onCreate()方法中,首先获取布局管理器中添加的作为地址栏的EditText组件、GO按钮和WebView组件,然后让WebView组件支持JavaScript,并为WebView组件设置处理各种通知和请求事件,具体代码如下:
- urlText=(EditText)findViewById(R.id.editText_url); //获取布局管理器中添加的地址栏
- goButton=(Button)findViewById(R.id.button_go); //获取布局管理器中添加的GO按钮
- webView=(WebView)findViewById(R.id.webView1); //获取WebView组件
- webView.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
- webView.setWebChromeClient(new WebChromeClient()); //处理JavaScript对话框
- //处理各种通知和请求事件,如果不使用该句代码,将使用内置浏览器访问网页
- webView.setWebViewClient(new WebViewClient());
说明:在上面的代码中,加粗的代码一定不能省略,如果不使用该句代码,将使用内置浏览器访问网页。
(4)获取布局管理中添加的“前进”按钮和“后退”按钮,并分别为它们添加单击事件监听器,在“前进”按钮的onClick()方法中调用goForward()方法实现前进功能;在“后退”按钮的onClick()方法中调用goBack()方法实现后退功能。具体代码如下:
- Button forward=(Button)findViewById(R.id.forward); //获取布局管理器中添加的“前进”按钮
- forward.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- webView.goForward(); //前进
- }
- });
- Button back=(Button)findViewById(R.id.back); //获取布局管理器中添加的“后退”按钮
- back.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- webView.goBack(); //后退
- }
- });
(5)为地址栏添加键盘按键被按下的事件监听器,实现当按下键盘上的Enter键时,如果地址栏中的URL地址不为空,则调用openBrowser()方法浏览网页;否则,调用showDialog()方法弹出提示对话框。具体代码如下:
- urlText.setOnKeyListener(new OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if(keyCode==KeyEvent.KEYCODE_ENTER){ //如果为Enter键
- if(!"".equals(urlText.getText().toString())){
- openBrowser(); //浏览网页
- return true;
- }else{
- showDialog(); //弹出提示对话框
- }
- }
- return false;
- }
- });
(6)为GO按钮添加单击事件监听器,实现单击该按钮时,如果地址栏中的URL地址不为空,则调用openBrowser()方法浏览网页;否则,调用showDialog()方法弹出提示对话框。具体代码如下:
- goButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if(!"".equals(urlText.getText().toString())){
- openBrowser(); //浏览网页
- }else{
- showDialog(); //弹出提示对话框
- }
- }
- });
(7)编写openBrowser()方法,用于浏览网页,具体代码如下:
- private void openBrowser(){
- webView.loadUrl(urlText.getText().toString()); //浏览网页
- Toast.makeText(this, "正在加载:"+urlText.getText().toString(), Toast.LENGTH_SHORT).show();
- }
(8)编写showDialog()方法,用于显示一个带“确定”按钮的对话框,通知用户输入要访问的网址。showDialog()方法的具体代码如下:
- private void showDialog(){
- new AlertDialog.Builder(MainActivity.this)
- .setTitle("网页浏览器")
- .setMessage("请输入要访问的网址")
- .setPositiveButton("确定",new DialogInterface.OnClickListener(){
- public void onClick(DialogInterface dialog,int which){
- Log.d("WebWiew","单击确定按钮");
- }
- }).show();
- }
(9)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
运行本实例,单击GO按钮,将访问地址栏中指定的网站,单击“前进”和“后退”按钮,将实现类似于IE浏览器上的前进和后退功能。实例运行结果如图14.13所示。
图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,具体代码如下:
- private WebView webView; //声明WebView组件的对象
(3)在onCreate()方法中,首先获取布局管理器中添加的WebView组件,然后设置该组件允许使用JavaScript,并处理JavaScript对话框和各种请求事件,再为WebView组件指定要加载的天气预报信息,最后将网页内容放大4倍,具体代码如下:
- webView=(WebView)findViewById(R.id.webView1); //获取WebView组件
- webView.getSettings().setJavaScriptEnabled(true); //设置JavaScript可用
- webView.setWebChromeClient(new WebChromeClient()); //处理JavaScript对话框
- //处理各种通知和请求事件,如果不使用该句代码,将使用内置浏览器访问网页
- webView.setWebViewClient(new WebViewClient());
- webView.loadUrl("http://m.weather.com.cn/m/pn12/weather.htm "); //设置默认显示的天气预报信息
- webView.setInitialScale(57*4); //放网页内容放大4倍
(4)让MainActivity实现OnClickListener接口,用于添加单击事件监听器。修改后的代码如下:
- public class MainActivity extends Activity implements OnClickListener{
(5)重写onClick()方法,用于为屏幕中的各个按钮的单击事件设置不同的响应,也就是在单击各个按钮时,调用openUrl()方法获取不同地区的天气预报信息,具体代码如下:
- @Override
- public void onClick(View view){
- switch(view.getId()){
- case R.id.bj: //单击的是“北京”按钮
- openUrl("101010100T");
- break;
- case R.id.sh: //单击的是“上海”按钮
- openUrl("101020100T");
- break;
- case R.id.heb: //单击的是“哈尔滨”按钮
- openUrl("101050101T");
- break;
- case R.id.cc: //单击的是“长春”按钮
- openUrl("101060101T");
- break;
- case R.id.sy: //单击的是“沈阳”按钮
- openUrl("101070101T");
- break;
- case R.id.gz: //单击的是“广州”按钮
- openUrl("101280101T");
- break;
- }
- }
(6)获取布局管理器中添加的“北京”按钮、“上海”按钮、“哈尔滨”按钮、“长春”按钮、“沈阳”按钮和“广州”按钮,并分别为它们添加单击事件监听器,具体代码如下:
- Button bj=(Button)findViewById(R.id.bj); //获取布局管理器中添加的“北京”按钮
- bj.setOnClickListener(this);
- Button sh=(Button)findViewById(R.id.sh); //获取布局管理器中添加的“上海”按钮
- sh.setOnClickListener(this);
- Button heb=(Button)findViewById(R.id.heb); //获取布局管理器中添加的“哈尔滨”按钮
- heb.setOnClickListener(this);
- Button cc=(Button)findViewById(R.id.cc); //获取布局管理器中添加的“长春”按钮
- cc.setOnClickListener(this);
- Button sy=(Button)findViewById(R.id.sy); //获取布局管理器中添加的“沈阳”按钮
- sy.setOnClickListener(this);
- Button gz=(Button)findViewById(R.id.gz); //获取布局管理器中添加的“广州”按钮
- gz.setOnClickListener(this);
(7)编写用于打开网页获取天气预报信息的方法openUrl(),在该方法中,将根据传递的参数不同,获取不同地区的天气预报信息,具体代码如下:
- private void openUrl(String id){
- webView.loadUrl("http://m.weather.com.cn/m/pn12/weather.htm?id="+id+" "); //获取并显示天气预报信息
- }
说明:在中国天气网(http://www.weather.com.cn/)中提供了单城市24小时天气预报插件,使用该插件可以实现在Android中获取指定城市的天气预报。
(8)由于在本实例中需要访问网络资源,所以还需要在AndroidManifest.xml文件中指定允许访问网络资源的权限,具体代码如下:
- <uses-permission android:name="android.permission.INTERNET"/>
运行本实例,在屏幕上将显示默认城市的天气预报信息,单击上方的“北京”、“上海”、“哈尔滨”、“长春”、“沈阳”和“广州”按钮,将显示对应城市的天气预报信息。例如,单击“长春”按钮,将显示如图14.14所示的效果。
图14.14 获取长春市的天气预报
14.4 小 结
本章首先介绍了如何通过HTTP访问网络,主要有两种方法:一种是使用java.net包中的HttpURLConnection实现;另一种是通过Android提供的HttpClient实现。对于一些简单的访问网络的操作,可以使用HttpURLConnection实现,但是如果操作比较复杂,就需要使用HttpClient来实现了。之后介绍了使用Android提供的WebView组件来显示网页,使用该组件可以很方便地实现基本的网页浏览器功能。
14.5 实践与练习
编写Android项目,在发送GET请求时,不使用Base64编码来解决中文乱码问题。(答案位置:光盘\TM\sl\14\14.12)
编写Android项目,实现使用系统内置的浏览器打开指定网页。(答案位置:光盘\TM\sl\14\14.13)