Android网络功能开发(2)——使用HTTP协议

使用HTTP协议或TCP/UDP协议都可以实现应用和服务器之间的通信,这两种方式各有优缺点。使用HTTP协议的好处是:服务器端有成熟的Web服务器来处理通信中的很多问题,开发者只需关注业务逻辑;缺点是HTTP协议只支持一问一答的通信方式,不能像聊天一样随意地互相发送消息。

Android使用HTTP协议主要是作为客户端,用HTTP GET方法从服务器获取数据,用HTTP POST方法向服务器传送数据。在Android上发送HTTP请求的方式不止一个,分别借助不同的工具类。HttpURLConnection是Java自带的HTTP访问接口,它是一个轻量极的HTTP客户端,轻便,灵活,易于扩展,但使用起来相对复杂一点。

本文介绍的是用HttpURLConnection类来发送HTTP请求。用HttpURLConnection发送HTTP请求的流程是:创建对象、设置参数、建立连接、传输数据、处理返回的数据。

使用HttpURLConnection或其它类实现网络功能时,还需注意:

  1. 字符编码问题(动画显示字符编码),客户端和服务器端应采用一致的字符编码,否则可能会出现乱码,现在一般都用utf-8。
  2. Http Get方法和Post方法在发送流程和参数上的区别。
  3. 网络操作不能在主线程中执行,只能另开线程,异步执行。
  4. 应用需要INTERNET权限。

我们通过一个的例子来介绍如何实现HTTP GET和POST。这个例子是一个最简化的BBS系统原型。有一个Android客户端和Web服务器端。

Android端通过HTTP Get从Web服务器获取所有帖子内容,通过HTTP Post将发表的新帖发送到Web服务器。服务器端用JavaEE开发,用一个Servlet来响应HTTP请求,用一个List来保存所有帖子。服务器端还设计了一个网页,用于测试和演示多客户端系统。

下面我们首先看Android端是如何实现的。首先看如何发送一个GET请求。我们把实现Get请求的代码封装到了一个方法中,叫做httpGet,参数是请求的URL,是一个字符串;返回值是服务器返回的消息内容,也保存到了一个字符串中。方法的主要代码就是按照使用HttpURLConnection发送HTTP请求的流程。

    String httpGet(String urlStr){
        String result = null;
        HttpURLConnection connection = null;
        try{
            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(5000);
            //connection.connect();	// 会自动进行
            int statusCode = connection.getResponseCode();
            if(statusCode==200) {
                InputStream in = connection.getInputStream();
                result = readInputStream(in);
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(connection!=null) connection.disconnect();
        }
        return result;
    }

首先创建HttpURLConnection对象,对应的代码是创建一个URL对象,再调用它的openConnection方法创建出HttpURLConnection对象。

然后是设置HTTP方法,对应的代码是调用connection对象的setRequestMethod方法,参数是字符串”GET”。

接着是设置参数,对应的代码中,设置了连接超时和读超时,单位是毫秒。

再接着是建立连接并传输数据,对应的代码是connection.connect()。这个方法如果不显式调用,也会自动调用。所以,即使不写这一句代码,也会自动建立连接并传输数据。

最后是处理返回的数据。先获取返回码,判断服务器对GET请求是否成功响应。返回码等于200表示成功,此时就可以打开一个输入流读取服务器返回的消息内容。这里我们把这些内容读到了一个字符串中,最后作为返回值返回。

这些代码涉及网络操作,可能会产生异常,所以要用try-catch语句进行处理。为了保证连接建立后就一定会断开,需要把断开连接的disconnect方法写到finally块中。

发送GET请求的代码,也就是上面我们写的httpGet方法,需异步执行。所谓异步执行,简单的说就是把代码在另一个单独的线程中执行,即使很耗时也不影响当前线程的继续执行。

如果在发送请求按钮的事件响应方法里面直接调用httpGet方法,那么发送GET请求的代码就会在主线程中执行,而网络操作可能比较耗时,会影响主线程对用户操作的响应,造成应用在此段时间内假死。所以,不能在事件响应方法中直接调用httpGet方法。

那么,如何实现代码的异步执行呢?可以用Android提供的AsyncTask类。具体步骤是创建一个AsyncTask对象,再执行它的execute方法。创建AsyncTask对象时要覆盖它的doInBackground方法和onPostExecute方法。doInBackground方法中的代码会在一个新的线程中执行;onPostExecute方法会在doInBackground方法结束后回调,并在主线程中执行,这样不影响其中的代码对界面控件的操作。所以在onPostExecute方法中,我们可以直接将结果字符串设置到界面最下方的TextView控件中显示。通过这个AsyncTask类,可以很方便地将网络传输放到子线程执行,同时又不违反子线程不能操作界面控件的规则,因为中间的参数传递和同步操作都已经封装在AsyncTask类中。这种方式用于网络传输等任务非常适合。

当然,这里为了代码清晰,我们用了一个字符串常量将URL传给了子线程,没有用execute方法的参数来传递。

完成了GET请求后,我们接着来看如何发送POST请求。与发送GET请求一样,发送POST请求的代码也是按照这个流程,写到了一个方法中,叫做httpPost。

    String httpPost(String urlStr, String content){
        String result = null;
        HttpURLConnection connection = null;
        try{
            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Charset", "UTF-8");
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            String params = "owner=Android&content=" + URLEncoder.encode(content, "UTF-8");
            OutputStream os = connection.getOutputStream();
            os.write(params.getBytes());
            os.flush();
            os.close();

            int statusCode = connection.getResponseCode();
            if(statusCode==200) {
                InputStream in = connection.getInputStream();
                result = readInputStream(in);
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(connection!=null) connection.disconnect();
        }
        return result;
    }

主要的区别是:

  1. 设置HTTP方法时参数是POST
  2. 设置参数后,把数据通过输出流写到了POST请求的消息体中

同样,发送POST请求的代码也需要通过AsyncTask异步执行,和GET请求的执行类似,这里不多解释。

到此为止,Android端发送GET和POST请求的代码就都完成了。

接下来,我们看服务器端如何实现。服务器端是用JavaEE开发的,开发工具用的Eclipse for JavaEE,Web服务器用的Tomcat。

服务器端的主要功能由一个Servlet实现。这个Servlet将所有发帖保存在posts中,这是一个Post对象的列表。一个Post对象保存发帖者和发帖内容。

这个Servlet负责响应客户端的请求。对于Get请求,将posts中所有内容返回,缺省是以纯文本格式返回。这里我们也预留了XML格式和JSON格式的接口,如果URL中有fmt参数并且fmt的值是2的时候,以XML格式返回posts中所有内容;fmt的值是3时,以JSON格式返回posts中所有内容。

对于Post请求,会把发帖者和内容保存到一个Post对象中,然后添加到posts列表中,最后返回一个Post OK的字符串,告诉客户端发帖成功。

除了这个Servlet以外,我们在服务器上再添加一个页面,叫content.html,负责对BBS Servlet进行测试,也可以演示多客户端系统。

BBS-content.png

这个页面上部是三个链接,都是以GET请求返回所有帖子内容,第一个链接对应于纯文本格式,第二个链接对应于XML格式,第三个链接对应于JSON格式。通过这三个链接,我们就可以测试BBS返回的帖子内容,也能看到数据的格式。页面下部是一个表单,对应于POST请求发表新帖。页面的代码也非常简单,就是三个超级链接和一个表单。

猜你喜欢

转载自blog.csdn.net/nanoage/article/details/127725595
今日推荐