zoukankan      html  css  js  c++  java
  • Android网络编程随想录(3)

            大多数Android的app都会使用HTTP协议来发送和接收数据。在Android开发中,通常使用两种http客户端:一个是Apache的HttpClient,另一个是HttpURLConnection。这两种HTTP客户端API都支持HTTPS协议,流数据上传和下载,配置超时,IPV6协议以及连接池等等。

    Apache HttpClient

            HttpClient的API众多,并且bug少比较稳定。但是,HttpClient的API比较大,很难在保证兼容性的前提下去对其进行扩展。所以很多Android团队并不太喜欢使用它。HttpClient是一个接口,里面封装了需要执行的http请求,身份验证,连接管理等等,有三个主要的实现类:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient。下面我们来看一下AndroidHttpClient,它对DefaultHttpClient进行了改进使之更适合于Android开发。于是,AndroidHttpClient进行请求发送和响应接收步骤如下:

    1. 创建HttpClient对象,通过静态方法newInstance()方法来获得AndroidHttpClient对象。
    2. 创建对应的发送请求的对象,如果需要发送GET请求,则创建HttpGet对象,如果需要发送POST请求,则创建HttpPost对象。
    3. 对于发送请求的参数,GET和POST使用的方式不同,GET方式可以使用拼接字符串的方式,把参数拼接在URL结尾;POST方式需要使用setEntity(HttpEntity entity)方法来设置请求参数。
    4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,执行该方法返回一个HttpResponse对象。
    5. 调用HttpResponse的对应方法获取服务器的响应头、响应内容等。

            通常情况下,我们并不在主线程中进行网络请求操作,而是新开一个子线程来进行网络操作,下面的代码展示了如何利用AndroidHttpClient完成网络登录验证的任务:

    public class LoginTask implements Runnable {
    
        private String username;
        private String password;
    
        public LoginTask(String username, String password) {
            // 初始化用户名和密码
            this.username = username;
            this.password = password;
        }
    
        @Override
        public void run() {
            // 设置访问的Web站点
            String path = "http://xxxx/loginas.aspx";
            //设置Http请求参数
            Map<String, String> params = new HashMap<String, String>();
            params.put("username", username);
            params.put("password", password);
    
            String result = sendHttpClientPost(path, params, "utf-8");
            //把返回的接口输出
            System.out.println(result);
        }
        /**
         * 发送Http请求到Web站点
         * @param path Web站点请求地址
         * @param map Http请求参数
         * @param encode 编码格式
         * @return Web站点响应的字符串
         */
        private String sendHttpClientPost(String path,Map<String, String> map,String encode)
        {
            List<NameValuePair> list=new ArrayList<NameValuePair>();
            if(map!=null&&!map.isEmpty())
            {
                for(Map.Entry<String, String> entry:map.entrySet())
                {
                    //解析Map传递的参数,使用一个键值对对象BasicNameValuePair保存。
                    list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            try {
                //实现将请求 的参数封装封装到HttpEntity中。
                UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode);
                //使用HttpPost请求方式
                HttpPost httpPost=new HttpPost(path);
                //设置请求参数到Form中。
                httpPost.setEntity(entity);
                //实例化一个默认的Http客户端,使用的是AndroidHttpClient
                HttpClient client=AndroidHttpClient.newInstance("");
                //执行请求,并获得响应数据
                HttpResponse httpResponse= client.execute(httpPost);
                //判断是否请求成功,为200时表示成功,其他均问有问题。
                if(httpResponse.getStatusLine().getStatusCode()==200)
                {
                    //通过HttpEntity获得响应流
                    InputStream inputStream=httpResponse.getEntity().getContent();
                    return changeInputStream(inputStream,encode);
                }
                
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            return "";
        }                    
        /**
         * 把Web站点返回的响应流转换为字符串格式
         * @param inputStream 响应流
         * @param encode 编码格式
         * @return 转换后的字符串
         */
        private  String changeInputStream(InputStream inputStream,
                String encode) { 
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = 0;
            String result="";
            if (inputStream != null) {
                try {
                    while ((len = inputStream.read(data)) != -1) {
                        outputStream.write(data,0,len);                    
                    }
                    result=new String(outputStream.toByteArray(),encode);
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    }

     

    HttpURLConnection

            相比之下,HttpURLConnection就显得更通用一些。它是一款多用途,轻量级的HTTP客户端,适用于大多数的app客户端。同时,HttpURLConnection简单,便于扩展。但是坑爹的是,在Android2.2之前,HttpURLConnection有一些bug,例如在试图关闭InputStream的时候会导致连接池失效。所以,推荐在2.3之后的版本中使用HttpURLConnection。

            下面以请求百度首页的logo为例子,演示使用HttpURLConnection的GET方法完成网络请求的任务:

    public class getImageTask{
        private static String URL_PATH = http://www.baidu.com/img/bd_logo1.png;
        /**
         * @param args
         */
        public static void main(String[] args) {
            // 调用方法获取图片并保存
            saveImageToDisk();
        }
        /**
         * 通过URL_PATH的地址访问图片并保存到本地
         */
        public static void saveImageToDisk()
        {
            InputStream inputStream= getInputStream();
            byte[] data=new byte[1024];
            int len=0;
            FileOutputStream fileOutputStream=null;
            try {
                //把图片文件保存在本地F盘下
                fileOutputStream=new FileOutputStream("F:\test.png");
                while((len=inputStream.read(data))!=-1) 
                {
                    //向本地文件中写入图片流
                    fileOutputStream.write(data,0,len);                
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            finally
            {
                //最后关闭流
                if(inputStream!=null)
                {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(fileOutputStream!=null)
                {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        /**
         * 通过URL获取图片
         * @return URL地址图片的输入流。
         */
        public static InputStream getInputStream() {
            InputStream inputStream = null;
            HttpURLConnection httpURLConnection = null;
    
            try {
                //根据URL地址实例化一个URL对象,用于创建HttpURLConnection对象。
                URL url = new URL(URL_PATH);
    
                if (url != null) {
                    //openConnection获得当前URL的连接
                    httpURLConnection = (HttpURLConnection) url.openConnection();
                    //设置3秒的响应超时
                    httpURLConnection.setConnectTimeout(3000);
                    //设置允许输入
                    httpURLConnection.setDoInput(true);
                    //设置为GET方式请求数据
                    httpURLConnection.setRequestMethod("GET");
                    //获取连接响应码,200为成功,如果为其他,均表示有问题
                    int responseCode=httpURLConnection.getResponseCode();
                    if(responseCode==200)
                    {
                        //getInputStream获取服务端返回的数据流。
                        inputStream=httpURLConnection.getInputStream();
                    }
                }
    
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return inputStream;
        }
    
    }

            如果使用POST方法,则需要设置请求参数。下面我们使用POST方式,利用HttpURLConnection完成和上面一样的登录验证功能:

    public class LoginTask implements Runnable{
    
        private static String PATH = "http://xxxxx/loginas.aspx";
        private static URL url;
    
        private String username;
        private String password;
        public LoginTask(String username, String password) {
             // 初始化用户名和密码 
            this.username = username; 
            this.password = password; 
        }
        /**
         * 通过给定的请求参数和编码格式,获取服务器返回的数据
         * @param params 请求参数
         * @param encode 编码格式
         * @return 获得的字符串
         */
        public static String sendPostMessage(Map<String, String> params,
                String encode) {
            StringBuffer buffer = new StringBuffer();
            if (params != null && !params.isEmpty()) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    try {
                        buffer.append(entry.getKey())
                                .append("=")
                                .append(URLEncoder.encode(entry.getValue(), encode))
                                .append("&");//请求的参数之间使用&分割。
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
    
                }
                buffer.deleteCharAt(buffer.length() - 1);
                System.out.println(buffer.toString());
                try {
                    HttpURLConnection urlConnection = (HttpURLConnection) url
                            .openConnection();
                    urlConnection.setConnectTimeout(3000);
                    //设置允许输入输出
                    urlConnection.setDoInput(true);
                    urlConnection.setDoOutput(true);
                    byte[] mydata = buffer.toString().getBytes();
                    //设置请求报文头,设定请求数据类型
                    urlConnection.setRequestProperty("Content-Type",
                            "application/x-www-form-urlencoded");
                    //设置请求数据长度
                    urlConnection.setRequestProperty("Content-Length",
                            String.valueOf(mydata.length));
                    //设置POST方式请求数据
                    urlConnection.setRequestMethod("POST");
                    OutputStream outputStream = urlConnection.getOutputStream();
                    outputStream.write(mydata);
                    int responseCode = urlConnection.getResponseCode();
                    if (responseCode == 200) {
                        return changeInputStream(urlConnection.getInputStream(),
                                encode);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return "";
        }
    
        /**
         * 把服务端返回的输入流转换成字符串格式
         * @param inputStream 服务器返回的输入流
         * @param encode 编码格式
         * @return 解析后的字符串
         */
        private static String changeInputStream(InputStream inputStream,
                String encode) { 
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = 0;
            String result="";
            if (inputStream != null) {
                try {
                    while ((len = inputStream.read(data)) != -1) {
                        outputStream.write(data,0,len);                    
                    }
                    result=new String(outputStream.toByteArray(),encode);
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    
        @Override
        public void run() {
            //通过Map设置请求字符串。
            try { 
                url = new URL(PATH); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
             
             Map<String, String> params = new HashMap<String, String>();
            params.put("username", "admin");
            params.put("password", "123");        
            String result=sendPostMessage(params, "utf-8");
            System.out.println(result);
        }
    
    }

     

    总结

            那么哪个客户端更好些呢?在2.2之前使用httpClient可以避免一些bug。而在2.3之后的版本中使用HttpURLConnection是最好的选择,简单的API适合于Android开发。透明压缩和应答数据的捕获,减少了网络的使用,提升了性能并且减少了电池的消耗。

            在随后我们介绍的开源库中,volley在2.3之前的版本中使用了HttpClient,而在2.3之后使用了HttpURLConnection;android-async-http中封装了HttpClient。

  • 相关阅读:
    hashmap的一些基础原理
    关于uuid
    读锁跟写锁的区别
    栈为什么效率比堆高
    MySQL行级锁、表级锁、页级锁详细介绍
    MYSQL MyISAM与InnoDB对比
    MYSQL锁表问题解决
    mysql查询锁表语句
    三种排序方法
    正则表达式
  • 原文地址:https://www.cnblogs.com/cqumonk/p/4821793.html
Copyright © 2011-2022 走看看