android 网络编程

来源:互联网 发布:lte mrr弱覆盖优化 编辑:程序博客网 时间:2024/04/30 14:05

安卓和Java应用开发少不了要提交HTTP请求,而基本上目前有两个实现方式:HttpUrlConnection(即URL.openConnection)和HttpClient。 HttpClient是apache的开源实现,而HttpUrlConnection是安卓标准实现。

1. HttpURLConnection

Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能。所以在Android 2.2版本以及之前的版本使用HttpClient是较好的选择,而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择,它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。另外在Android 6.0版本中,HttpClient库被移除了。

1.1 Get

首先需要获取到 HttpURLConnection 的实例,一般只需 new 出一个 URL 对象,并传入 目标的网络地址,然后调用一下 openConnection()方法即可。得到了 HttpURLConnection 的实例之后,我们可以设置一下 HTTP 请求所使用的方法。 常用的方法主要有两个,GET 和 POST。GET 表示希望从服务器那里获取数据,而 POST 则 表示希望提交数据给服务器。接下来就可以进行一些自由的定制了,比如设置连接超时、读取超时的毫秒数,以及服 务器希望得到的一些消息头等。这部分内容根据自己的实际情况进行编写。之后再调用 getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是 对输入流进行读取。接着利用 BufferedReader 对服务器 返回的流进行读取,并将结果存放到了一个 Message 对象中。这里为什么要使用 Message 对 象呢?当然是因为子线程中无法对 UI 进行操作了。我们希望可以将服务器返回的内容显示 到界面上,所以就创建了一个 Message 对象,并使用 Handler 将它发送出去。之后又在 Handler 的 handleMessage()方法中对这条 Message 进行处理。最后可以调用 disconnect()方法将这个 HTTP 连接关闭掉。

private void connectWithHttpURLConnection() {    new Thread( new Runnable() {        @Override        public void run() {            HttpURLConnection connection = null;            try {                // 调用URL对象的openConnection方法获取HttpURLConnection的实例                URL url = new URL("http://www.cnblogs.com/gzdaijie");                connection = (HttpURLConnection) url.openConnection();                // 设置请求方式,GET或POST                connection.setRequestMethod("GET");                // 设置连接超时、读取超时的时间,单位为毫秒(ms)                connection.setConnectTimeout(8000);                connection.setReadTimeout(8000);                // getInputStream方法获取服务器返回的输入流                InputStream in = connection.getInputStream();                // 使用BufferedReader对象读取返回的数据流                // 按行读取,存储在StringBuider对象response中                BufferedReader reader = new BufferedReader(new InputStreamReader(in));                StringBuilder response = new StringBuilder();                String line;                while ((line = reader.readLine()) != null) {                    response.append(line);                }                Message message = new Message();                 message.what = SHOW_RESPONSE;                // 将服务器返回的结果存放到Message中                 message.obj = response.toString();                handler.sendMessage(message);            } catch (Exception e){                e.printStackTrace();            } finally {                if (connection != null){                    // 结束后,关闭连接                    connection.disconnect();                }            }        }    }).start();}

1.2 Post

注意需要对中文进行设置编码格式

URLEncoder.encode(nickname.getText().toString(), “utf-8”)

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重定向            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();        }    }

2. HttpClient

HttpClient是Apache提供的库,提供了高效的、最新的支持HTTP协议的工具包,封装了众多的http请求、响应等方法,但有个缺点就是太重量级了,API太多了。

2.1 Get

首先你需要知道,HttpClient 是一个接口,因此无法创建它的实例,通常情况下都会创 建一个 DefaultHttpClient 的实例。接下来如果想要发起一条 GET 请求,就可以创建一个 HttpGet 对象,并传入目标的网络 地址,然后调用 HttpClient 的 execute()方法即可。执行 execute()方法之后会返回一个 HttpResponse 对象,服务器所返回的所有信息就会包 含在这里面。通常情况下我们都会先取出服务器返回的状态码,如果等于 200 就说明请求和响应都成功了。接下来在这个 if 判断的内部取出服务返回的具体内容,可以调用 getEntity()方法获取到 一个 HttpEntity 实例,然后再用 EntityUtils.toString()这个静态方法将 HttpEntity 转换成字符串 即可。注意如果服务器返回的数据是带有中文的,直接调用 EntityUtils.toString()方法进行转换 会有乱码的情况出现,这个时候只需要在转换的时候将字符集指定成 utf-8 就可以了。

    // 创建DefaultHttpClient实例    HttpClient httpClient = new DefaultHttpClient();          //传入网址,然后执行    HttpGet httpGet = new HttpGet("http://www.cnblogs.com/gzdaijie");    HttpResponse httpResponse = httpClient.execute(httpGet);     // 由状态码判断请求结果,    // 常见状态码 200 请求成功,404 页面未找到,关于HTTP的更多状态码直接GOOGLE    if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {               // 请求成功,使用HttpEntity获得返回数据        // 使用EntityUtils将返回数据转换为字符串        HttpEntity entity = httpResponse.getEntity();         String response = EntityUtils.toString(entity);        //如果是中文,指定编码         //==>String response = EntityUtils.toString(entity, "utf-8");         //或者生成一个BufferedReader        BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));    }

2.2 Post

    HttpClient httpClient = new DefaultHttpClient();    HttpPost httpPost("http://www.cnblogs.com/gzdaijie");      // 使用NameValuePair(键值对)存放参数    List<NameValuePair> data = new ArrayList<NameValuePair>();    // 添加键值对    data.add(new BasicNameValuePair("stu_no", 12345));    data.add(new BasicNameValuePair("stu_name", "Tom"));    // 使用setEntity方法传入编码后的参数    httpPost.setEntity(new UrlEncodedFormEntity(data, "utf-8"));     // 执行该POST请求    HttpResponse httpResponse = httpClient.execute(httpPost);    // .....省略处理httpResponse的代码,与GET方式一致 

3. 用回调函数实现网络编程

3.1 定义接口HttpCallbackListener,为了实现回调

在接口中定义了两个方法,onFinish()方法表示当服务器成功响应我们请 求的时候调用,onError()表示当进行网络操作出现错误的时候调用。这两个方法都带有参数, onFinish()方法中的参数代表着服务器返回的数据,而 onError()方法中的参数记录着错误的 详细信息。

// 定义HttpCallbackListener接口// 包含两个方法,成功和失败的回调函数定义public interface HttpCallbackListener {    void onFinish(String response);    void onError(Exception e);}

3.2 定义类HttpUtil,为了网络助手类

先给 sendHttpRequest()方法添加了一个 HttpCallbackListener 参数,并在方法的内 部开启了一个子线程,然后在子线程里去执行具体的网络操作。注意子线程中是无法通过 return 语句来返回数据的,因此这里我们将服务器响应的数据传入了 HttpCallbackListener 的 onFinish()方法中,如果出现了异常就将异常原因传入到 onError()方法中。

/* 创建一个新的类 HttpTool,将公共的操作抽象出来 * 为了避免调用sendHttpRequest方法时需实例化,设置为静态方法 * 传入HttpCallbackListener对象为了方法回调 * 因为网络请求比较耗时,一般在子线程中进行, * 为了获得服务器返回的数据,需要使用java的回调机制 */public class HttpTool {    public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {        new Thread(new Runnable() {            @Override            public void run() {                HttpURLConnection connection = null;                try {                    URL url = new URL(address);                    connection = (HttpURLConnection) url.openConnection();                    connection.setRequestMethod("GET");                    connection.setConnectTimeout(8000);                    connection.setReadTimeout(8000);                    InputStream in = connection.getInputStream();                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));                    StringBuilder response = new StringBuilder();                          String line;                    while ((line = reader.readLine()) != null) {                        response.append(line);                    }                    if (listener != null) {                        // 回调方法 onFinish()                        listener.onFinish(response.toString());                    }                } catch (Exception e) {                    if (listener != null) {                        // 回调方法 onError()                        listener.onError(e);                    }                } finally {                    if (connection != null) {                        connection.disconnect();                    }                }            }        }).start();    }}  

3.3 调用网络助手类

这样的话,当服务器成功响应的时候我们就可以在 onFinish()方法里对响应数据进行处 理了,类似地,如果出现了异常,就可以在 onError()方法里对异常情况进行处理。如此一来, 我们就巧妙地利用回调机制将响应数据成功返回给调用方了。
另外需要注意的是,onFinish()方法和 onError()方法最终还是在子线程中运行的,因此 我们不可以在这里执行任何的 UI 操作,如果需要根据返回的结果来更新 UI,则仍然要使用异步消息处理机制(Handler)。

//使用该HttpTool发起GET请求String url = "http://www.cnblogs.com/gzdaijie";HttpTool.sendHttpRequest(url,new HttpCallbackListener(){    @Override      public void onFinish(String response) {        // ...省略对返回结果的处理代码      }      @Override      public void onError(Exception e) {           // ...省略请求失败的处理代码    } });
0 0
原创粉丝点击