Android网络编程

一、概述

Android应用作为一个客户端程序绝大部分都是需要进行网络请求和访问的,而http通信是一种比较常见并常用的通信方式。

在Android中原生http网络编程中有两种实现方式,一种是使用HttpURLConnection,另一种就是使用HttpClient。现在使用更广泛的是HttpURLConnection

这两种实现方式的大体过程都是:

  • Android客户端向服务器发出请求。
  • 服务端接收请求并响应。
  • 服务端返回数据给客户端。

在Http通信中有POST和GET两种方式,其不同之处在于GET方式可以获得静态页面,同时可以将请求参数放在URL字符串后面,传递给服务器;而POST方式的参数则是放在Http请求中的。因此,无论你是用哪一种HTTP实现方式都需要明确所使用的请求方式。

二、HttpURLConnection

首先,我们来认识一下HttpURLConnection

HttpURLConnection根据使用目的不同,在具体使用时会稍有区别。下面,就常见的几种应用举例说明。

  • 从Internet获取网页,即向URL发送请求,将网页以流的形式读回本地。
  • 从Internet获取文件,即利用HttpURLConnection对象从网络中获取文件数据。
  • 向Internet发送请求参数,即向服务器传递参数,即向服务器传递参数
  • 向Internet传送XML数据。(使用HTTP的的方式传输文件,一般文件大小在5M一下,HTTP通信方式不适合传输大文件,对大文件的传输最好使用Socket通信方式,以保证程序的稳定性。)

下面我们以第一种为例:
我们设置获取网页为百度,
static String strurl = “http://www.baidu.com”;

public static void testHttpUrlConnection() {
// 开启线程发起网络请求
        new Thread(new Runnable() {
            private HttpURLConnection conn;

            public void run() {
                
                try {
                    URL url = new URL(strurl);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");//设置请求方式为GET
                    conn.setConnectTimeout(6 * 1000);//设置连接超时的时间
                    conn.setReadTimeout(8000);//设置读取超时的毫秒数
                    
                    if (conn.getResponseCode() != 200)//判断是否请求成功
                        throw new RuntimeException("运行异常");
                    //获取服务器返回的输入流
                    InputStream is = conn.getInputStream();
                    String str = convertStreamToString(is);
                    System.out.println("HttpUrlConnection方式"+str);

                } catch (Exception e) {
                    System.out.println("utils异常");
                    e.printStackTrace();
                }
                //关闭http链接
                conn.disconnect();
            }
        }).start();

    }

我们可以看到,首先通过(HttpURLConnection) url.openConnection()返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。然后我们需要将将流转换成字符串

/**
     * 将流转换成字符串
     * 
     * @param is
     * @return
     */
    public static String convertStreamToString(InputStream is) {
        /*
         * To convert the InputStream to String we use the
         * BufferedReader.readLine() method. We iterate until the BufferedReader
         * return null which means there's no more data to read. Each line will
         * appended to a StringBuilder and returned as String.
         */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return sb.toString();
    }

HttpURLConnection继承于URLConnection类,二者都是抽象类。其对象主要通过URL对象的openConnection方法创建,在获得HttpURLConnection对象之后,默认采用GET方式请求数据,此时即可使用输入流读取信息。

URL url = new URL(strurl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");//设置请求方式
conn.setConnectTimeout(6 * 1000);//设置连接超时的时间
conn.setReadTimeout(8000);//设置读取超时的毫秒数
if (conn.getResponseCode() != 200)//判断是否请求成功
          throw new RuntimeException("运行异常");
//获取服务器返回的输入流
InputStream is = conn.getInputStream();

如果使用POST方式,还需要对一些参数进行设置(包括上面示例中的一些设置,除此之外还有以下常见设置)。

 url = new URL(path);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("POST");// 提交模式
            // conn.setConnectTimeout(10000);//连接超时 单位毫秒
            // conn.setReadTimeout(2000);//读取超时 单位毫秒
            // 发送POST请求必须设置如下两行
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
            // 发送请求参数
            printWriter.write(post);//post的参数 xx=xx&yy=yy
            //以下设置一般请求属性,即网页的头部信息
                    conn.setRequestProperty("Charset", "UTF-8");
                 conn.setRequestProperty("Connection", "Keep-Alive");
                 conn.setRequestProperty("Content-Type", "application/x-www-from-urlencoded");
                 conn.setRequestProperty("Content-Length", String.valueOf(data.length));
                 
            // flush输出流的缓冲
            printWriter.flush();
            //开始获取数据
            BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

还有一些其他属性


                    conn.setUseCaches(false);//是否使用缓存
                    conn.setInstanceFollowRedirects(true);//是否自动执行http重定向
                    

OKHttp

android网络框架之OKhttp一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso)用于替代HttpUrlConnection。
在AndroidStudio中使用不需要下载jar包,直接添加依赖即可:
compile ‘com.squareup.okhttp3:okhttp:3.4.1’
当然,这可能已经不是最新的版本了,你们可以去GitHub查看最新版本https://github.com/square/okhttp
下面简单介绍一下OKHttp的使用

1、GET请求

OKHttp中网络请求分为同步、异步两种
异步GET请求
首先,我们创建一个OKHttpClient示例

OkHttpClient okHttpClient = new OkHttpClient();

然后我们需要一个Request对象

Request request = new Request.Builder()
        .url(url)
        .get()//默认就是GET请求,可以不写
        .build();

之后通过前两步中的对象构建Call对象

Call call = okHttpClient.newCall(request);

最后通过通过Call.enqueue(Callback)方法来提交异步请求.
代码如下

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .get()//默认就是GET请求,可以不写
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: ");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

其中Response对象就是服务器返回的数据了

同步GET请求

前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute() 来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0 以后已经不允许在主线程访问网络。

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Response response = call.execute();
            Log.d(TAG, "run: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

注意:
1,response.body().string()本质是输入流的读操作,所以它还是网络请求的一部分,所以这行代码必须放在子线程。
2,response.body().string()只能调用一次,在第一次时有返回值,第二次再调用时将会返回null。原因是:response.body().string()的本质是输入流的读操作,必须有服务器的输出流的写操作时客户端的读操作才能得到数据。而服务器的写操作只执行一次,所以客户端的读操作也只能执行一次,第二次将返回null。

2、POST请求

Post请求也分同步和异步两种方式,同步与异步的区别和get方法类似,所以此时只讲解post异步请求的使用方法。

private void postDataWithParame() {
OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。
FormBody.Builder formBody = new FormBody.Builder();//创建表单请求体
formBody.add("username","zhangsan");//传递键值对参数
Request request = new Request.Builder()//创建Request 对象。
        .url("http://www.baidu.com")
        .post(formBody.build())//传递请求体
        .build();
client.newCall(request).enqueue(new Callback() {。。。});//回调方法的使用与get异步请求相同,此时略。
}

POST方式提交流

RequestBody requestBody = new RequestBody() {
    @Nullable
    @Override
    public MediaType contentType() {
        return MediaType.parse("text/x-markdown; charset=utf-8");
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        sink.writeUtf8("I am Jdqm.");
    }
};

Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

POST提交文件

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File("test.md");
Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(mediaType, file))
        .build();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

你可能感兴趣的:(Android网络编程)