目录

一、使用HttpUrlConnection访问网络

1、发送GET请求

tips: 如何处理302重定向

2、发送POST请求

二、OkHttp的使用方法

三、WebView的使用方法


 

一、使用HttpUrlConnection访问网络

在Android 6.0以前,Android上发送HTTP请求一般有两种方式,HttpUrlConnection和HttpClient。HttpClient是Apache的开源库,存在API数量过多、扩展困难等缺点,在Android6.0系统中,将HttpClient的功能完全移除了。官方建议使用HttpUrlConnection来进行网络请求。

1、发送GET请求

/*
    使用HttpUrlConnection发送GET请求
    */
    public static void sendHttpGetRequest(final String address){
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL url = null;//请求的url地址
                HttpURLConnection conn = null;
                InputStream is = null;
                ByteArrayOutputStream baos = null;

                String requestHeader = null;//请求头
                String requestBody = null;//请求体
                String responseHeader = null;//响应头
                String responseBody = null;//响应体

                try {
                    //创建一个URL对象
                    url = new URL(address);
                    //打开一个HttpUrlConnection连接
                    conn = (HttpURLConnection)url.openConnection();
                    //设置GET、POST请求方式,默认使用GET发送请求
                    conn.setRequestMethod("GET");
                    //设置连接超时时间
                    conn.setConnectTimeout(5000);
                    //设置从服务器读取数据超时时间
                    conn.setReadTimeout(5000);
                    //设置是否使用缓存,默认true
                    conn.setUseCaches(true);
                    //设置从服务端读取结果流,默认true
                    conn.setDoInput(true);
                    //用来设置请求头
                    conn.setRequestProperty("Connection", "Keep-Alive");
                    conn.setRequestProperty("TestDemo", "GET");
                    //在对各种参数配置完成后,通过调用connect方法建立TCP连接,但是并未真正获取数据
                    //connect()方法不必主动调用,当调用getInputStream()方法时内部也会自动调用connect方法
                    conn.connect();

                    if(conn.getResponseCode() == 200){
                        //调用getInputStream方法后,服务端才会收到请求,并阻塞式地接收服务端返回的数据
                        is = conn.getInputStream();
                        baos = new ByteArrayOutputStream();
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while((len = is.read(bytes)) != -1){
                            baos.write(bytes, 0, len);
                        }
                        requestBody = baos.toString();
                        Log.d(TAG, "run: response " + requestBody);
                    }else if(conn.getResponseCode() == 302){
                        //处理重定向,这里只是一个简单的例子,不是标准写法
                        String location = conn.getHeaderField("Location");
                        url = new URL(location);
                        //打开一个HttpUrlConnection连接
                        conn = (HttpURLConnection)url.openConnection();
                        conn.setRequestMethod("GET");
                        conn.setConnectTimeout(5000);
                        conn.setReadTimeout(5000);
                        conn.setUseCaches(true);
                        conn.connect();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    try {
                        if (baos != null){
                            baos.close();
                        }
                        if(is != null){
                            is.close();
                        }
                        if(conn != null){
                            conn.disconnect();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }

            }
        }).start();

    }

tips: 如何处理302重定向

1、网络请求属于耗时操作,不可以在主线程内进行,需要单独起一个线程进行网络请求操作;

2、HttpUrlConnection有两个方法来设置是否自动处理重定向setFollowRedirects()和setInstanceFollowRedirects(),但我设置后访问http://www.baidu.com,并没有自动重定向,还会返回302的错误码,手动处理后,可以获取response header里的Location,是重定向后的url。而OkHttp可以自动处理重定向,okhttp的重定向默认是开启的,可以手动设置为关闭。

 

2、发送POST请求

/*
    * 使用HttpUrlConnection发送POST请求
    * */
    public static void sendHttpPostRequest(final String address){
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL url = null;
                HttpURLConnection conn = null;
                DataOutputStream dos = null;
                InputStream is = null;
                ByteArrayOutputStream baos = null;

                String requestHeader = null;//请求头
                String requestBody = null;//请求体
                String responseHeader = null;//响应头
                String responseBody = null;//响应体

                try {
                    //创建一个URL对象
                    url = new URL(address);
                    //打开一个HttpUrlConnection连接
                    conn = (HttpURLConnection)url.openConnection();
                    //设置请求方式为POST,必须设置,默认GET
                    conn.setRequestMethod("POST");
                    //设置允许输出,POST请求必须设置,默认false
                    conn.setDoOutput(true);
                    //设置请求默认输入,默认true
                    conn.setDoInput(true);
                    //设置请求头
                    conn.setRequestProperty("TestDemo", "POST");
                    //设置连接超时时间
                    conn.setConnectTimeout(5000);
                    //设置从服务器读取数据超时时间
                    conn.setReadTimeout(5000);
                    //设置本次连接是否自动处理重定向
                    conn.setInstanceFollowRedirects(true);
                    //开始连接
                    conn.connect();
                    //发送请求的POST参数,键值对形式
                    dos = new DataOutputStream(conn.getOutputStream());
                    dos.writeBytes("username=prance&password=123456");
                    dos.flush();
                    dos.close();
                    if(conn.getResponseCode() == 200){
                        is = conn.getInputStream();
                        baos = new ByteArrayOutputStream();
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while((len = is.read(bytes))!=-1){
                            baos.write(bytes, 0 , len);
                        }
                        responseBody = baos.toString();
                        Log.d(TAG, "run: response" + responseBody);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    try {
                        if (baos != null){
                            baos.close();
                        }
                        if(is != null){
                            is.close();
                        }
                        if(conn != null){
                            conn.disconnect();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

二、OkHttp的使用方法

    1、添加OkHttp库的依赖

       在app/build.gradle文件中,dependencies闭包中加入依赖:

dependencies {
       ......
       implementation 'com.squareup.okhttp3:okhttp:3.12.1'
}

     2、使用方法

      (1)Get请求

/*发送HTTP Get请求
    * 参数:
    *    address:请求的url地址
    * */
    public static void sendOkHttpRequest(final String address){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //创建一个OkHttpClient的实例
                OkHttpClient okHttpClient = new OkHttpClient();
                //创建一个Request对象
                Request request = new Request.Builder().url(address).build();
                try {
                    //调用OkHttpClient的newCall()方法来创建一个Call对象,通过它的execute()方法来发送请求并获取服务器返回的数据
                    Response response = okHttpClient.newCall(request).execute();
                    Log.d(TAG, "run: " + response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

需要注意的是,发送网络请求属于耗时操作,无法在UI线程(主线程)进行,使用的时候一定单独起一个子线程去发送网络请求,否则会抛出android.os.NetworkOnMainThreadException的异常导致程序崩溃。

因此,OkHttp提供了一个回调接口,可供调用方有时机去处理服务器返回的数据

/*发送HTTP Get请求
 * 参数:
 *    address: 请求的url地址
 *    callback: OkHttp回调接口
 * */

public static void sendOkHttpRequest2(String address, Callback callback){
    //创建一个OkHttpClient的实例
    OkHttpClient okHttpClient =  new OkHttpClient();
    //创建一个Request对象
    Request request = new Request.Builder().url(address).build();
    //调用OkHttpClient的newCall()方法来创建一个Call对象
    //enqueue()方法内部会开启一个子线程去执行http请求,并将最终的请求结果回调到Callback中
    okHttpClient.newCall(request).enqueue(callback);
}

调用方式:

HttpUtilty.sendOkHttpRequest("http://www.baidu.com", new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "http connected failed", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: " + response.body().string());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "success", Toast.LENGTH_SHORT).show();
            }
        });


    }
});

需要注意的是,Callback最终的回调接口还是在okhttp起的子线程中运行的,因此不可以直接在回调接口里执行任何UI操作,可以借助runOnUiThread()方法来进行线程切换。

(2)Post请求     

public static void sendOkHttpPostRequest(String address, Callback callback){
    //创建一个OkHttpClient的实例
    OkHttpClient okHttpClient =  new OkHttpClient ();
    //构建一个RequestBody对象来存放待提交的参数
    RequestBody requestBody = new FormBody.Builder()
            .add("username", "admin")
            .add("password", "123456")
            .build();
    //创建一个Request对象
    Request request = new Request.Builder()
            .url(address)
            .post(requestBody)
            .build();
    //调用OkHttpClient的newCall()方法来创建一个Call对象
    //enqueue()方法内部会开启一个子线程去执行http请求,并将最终的请求结果回调到Callback中
    okHttpClient.newCall(request).enqueue(callback);
}

 

三、WebView的使用方法

Android提供了一个WebView控件,借助它可以在自己的应用程序里嵌入一个浏览器,从而非常轻松的展示各种各样的网页。

1、创建一个布局文件,引入WebView控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/title_layout"/>
    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

2、在Activity中使用WebView控件

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_demo);
        WebView webView = findViewById(R.id.webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("http://www.baidu.com");

    }

注意,这里使用了WevView的setWebViewClient()方法,并传入了一个WevViewClient的实例,作用是,希望目标网页仍然在当前WebView中展示,而不是打开系统浏览器。如果没有设置这个,那应用中会弹窗提示使用哪个浏览器打开目标网页,而不会在当前你自己的应用中展现网页。