Android开发——HttpURLConnection

Android应用中,HttpURLConnection类用于在客户端和服务器之间使用HTTP协议明文交换数据,但在Android 9以后版本中,默认是不允许明文传输数据的;如果使用HttpURLConnection类,则需要在AndroidManifest.xml文件中的<application>标记中添加android:usesCleartextTraffic="true"属性,以便允许明文信息交换。

HttpURLConnection类的应用是比较灵活的,实际开发时,可以进行封装后以简化应用。如下面的代码就是作者封装的CHttp类中的getText()方法,用于通过HttpURLConnection类进行数据交换。

Java
package com.caohuayu.chy;
import android.net.Uri;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Hashtable;
import java.util.UUID;
public class CHttp {
    public static String getText(String addr, int timeout,final String[] args)
    {
        HttpURLConnection cnn = null;
        String result = null;
        try{
            URL url = new URL(addr);
            // 读取参数
            StringBuilder sb = new StringBuilder();
            int maxIndex = args.length;
            for(int i=0;i<maxIndex;i+=2) {
                sb.append(args[i]);
                sb.append("=");
                sb.append(URLEncoder.encode(args[i+1], "utf8"));
                sb.append("&");
            }
            // 删除最后一个&
            if(sb.length() > 0)
                sb.deleteCharAt(sb.length()-1);
            //
            cnn = (HttpURLConnection)url.openConnection();
            cnn.setRequestMethod("POST");
          // 设置编码格式
            cnn.setRequestProperty("Charset", "UTF-8");
            // 设置容许输出
            cnn.setDoOutput(true);
            cnn.setDoInput(true);
            cnn.setReadTimeout(timeout);
            cnn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            cnn.setRequestProperty("Content-Length",String.valueOf(sb.toString().length()));
            cnn.setRequestProperty("User-Agent",
                "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            cnn.connect();
            //
            DataOutputStream output =
                 new DataOutputStream(cnn.getOutputStream());
            output.writeBytes(sb.toString());
            //
            InputStream s;
            int status = cnn.getResponseCode();
            if (status != HttpURLConnection.HTTP_OK) {
                result = String.valueOf(status);
            } else {
                s = cnn.getInputStream();
                //
                BufferedReader reader =
                     new BufferedReader(new InputStreamReader(s));
                StringBuilder sb1 = new StringBuilder();
                String ln;
                while ((ln = reader.readLine()) != null) {
                    sb1.append(ln);
                }
                result = sb1.toString();
            }
        }catch (Exception ex){
            ex.printStackTrace();
            result = "";
        }finally {
            if(cnn != null) cnn.disconnect();
            return result;
        }
    }
}

代码中,getText()方法的参数包括:

  • String addr,定义获取资源的网址。
  • int timeout,定义超时时间,单位为毫秒。
  • final String[] args,定义获取资源时的参数,使用key1,value1,key2,value2,...格式进行。

返回值,getText()方法会返回从addr获取的文本内容。

下面,了解一些HttpURLConnection类中的常用成员。

  • setRequestMethod()方法设置请求网络资源的连接方法。使用GET方式时,如果需要同时提交参数,应将参数放在URL地址一起,如“http://10.0.2.2/index.html?id=123”;如果使用POST方式,参数需要创建一个新的连接发送到服务器。
  • setDoInput()和setDoOutput()方法,设置是否允许在服务器写入数据和读取数据,可以根据实际需要设置。
  • setRequestProperty()方法,用于设置向服务器提交数据时的参数,这里设置参数包括设置字符集为UTF-8,并模拟HTML表单提交数据。
  • setConnectTimeout()和setReadTimeout()方法,分别设置连接和读取内容的超时时间,单位是毫秒,如果设置为10秒,方法的参数就应该设置为10000。
  • getInputStream()方法,从网络资源中读取内容,其格式为InputStream对象,很多情况下,需要将InputStream对象转换为文本内容。

开发中,对于获取网络资源这种操作,一般会放在一个新的线程中执行,当获取的资源需要在Activity界面处理时,则需要注意runOnUiThread()方法的应用,可参考下面的代码模板。

Java
final String addr = "";
final String[] args = new String[]{"key1","value1", "key2", "value2"};
new Thread(new Runnable() {
   @Override
   public void run() {final String result = CHttp.getText(addr,10000, args);
      runOnUiThread(new Runnable() {
         @Override
         public void run() {
            // 处理result中的文本内容
            }
         }
      });
   }}).start();