Android的网络编程

网络的基本概念及Http协议

网络的基本知识

IP地址和端口号

  • IP地址:网络中的每台计算机都必须有一个唯一的IP地址作为标识,用一组由“.”分隔的十进制数组成
  • 端口号:IP地址只能保证将数据送到指定的计算机,但无法找到交给该主机的哪个网络程序,因此采用端口号标识计算机上正在运行的进程
  • 每个被发送的网络数据包都包含端口号,用于将该数据帧交给具有相同端口号的应用程序处理

Java的网络编程由java.net包中的类进行处理

  • InetAddress类:描述IP地址
HTTP协议

属于应用层的面向对象的协议,适用分布式超媒体信息系统

主要特点

  • 支持C/S模式
  • 简单快递:只需传送请求方法和路径,请求方法常用的有:GET、HEAD、POST等
  • 灵活:允许传输任意类型的数据对象,用Content-Type进行标记
  • 无连接:限制每次连接只处理一个请求
  • 无状态:对事物处理没有记忆功能

HTTP的URL的格式

  • http://host[:port][/path]
  • http表示要通过HTTP协议定位网络资源;host表示合法的Internet主机域名或者IP地址;port指定一个端口号,为空则使用默认端口80;path指定请求资源的URL
HTTP请求报文

由请求行、请求报文、空行和请求数据4个部分组成

具体介绍

  • 请求行(request line):声明请求方法、主机域名、资源路径&协议版本
  • 请求头(header):声明客户端、服务器/报文的部分信息
  • 请求体:存放需要发送的数据信息
HTTP响应报文

由状态行、消息报头、空行、响应正文组成

具体介绍

  • 状态行:声明协议版本,状态码,状态码描述
  • 响应头:声明客户端、服务器/报文的部分信息
  • 响应体:存放需发送的数据信息
常见的状态码
  • 200 OK:客户端请求成功
  • 400 Bad Request:客户端请求有语法错误,不能被服务器所理解
  • 401 Unauthorized:请求未经授权,这个状态码必须和WWW-Authenticate报头域一起使用
  • 403 Forbidden:服务器收到请求,但是拒绝提供服务
  • 404 Not Found:服务器无法根据客户端的请求找到资源
  • 500 Internal Server Error:服务器发生不可预期的错误
  • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常
https请求
  • HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,也就是HTTP的安全版
  • HTTPS = HTTP + SSL/TLS
  • HTTPS的安全基础是SSL

Android的网络编程

Http通信方式

  • HttpURLConnection
    Android2.3之后,HttpURLConnection是Android网络编程的最佳选择,它的API简单,体积较小,压缩和缓存机制有效较少网络访问的流量

  • HttpClient
    1、开发团队向开发者建议:在Android2.2版本及以下可以使用HttpClient,在2.3以上版本则应该使用HttpURLConnection
    2、Android6.0直接删除了HttpClient类库

  • Socket通信方式

Android P的http网络请求的问题

更改网络安全配置

  • 在res新增xml目录,创建network_security_config.xml,开启http请求
<?xml version="1.0" encoding="utf-8"?>
<network-security-config >
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>
  • 在AndroidManifest.xml中的application标签增加以下属性
android:networkSecurityConfig="@xml/network_security_config"
Android的Https

自定义X509TrustManager

  • 在使用HttpsURLConnection发起HTTPS请求的时候,提供了一个自定义的X509TrustManager,为实现安全校验逻辑
  • 如果不提供自定义X509TrustManager,代码运行起来可能会报异常

自定义HostnameVerifier

  • 在握手期间,如果URL的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接
URL类
  • 统一资源定位符(URL)是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
  • 互联网上的每个文件都有一个唯一的URL
  • URL类提供了多个 构造器用于创建URL对象
  • URL类提供多个方法访问URLduiying的资源:
    1、URLConnection openConnection():返回一个URLConnection对象,它表示到URL所引用的远程对象的连接
    2、InputStream openStream():打开此URL的连接,并返回一个用于读取该URL资源的InputStream
Android URL通信

Android HTTP URL接口的基本操作包括:

  • 创建URL以及HTTPURLConnection对象
  • 连接参数设置
  • 连接到服务器
  • 向服务器写数据
  • 从服务器读取数据

HTTPURLConnection的属性设置

connection.setConnectTimeout(15000);
connection.setReadTimeout(15000);
connection.setRequestProperty("Connection","Keep-Alive");
connection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36");
connection.setDoInput(true);
connection.setDoOutput(true);

HTTPURLConnection访问HTTP资源的步骤:

  • 根据URL地址创建URL对象
  • 使用URL对象的openConnection()方法获取HTTPURLConnection对象
  • 设置连接的属性,包括GET/POST请求方式
  • 输入、输出数据
  • 关闭输入、输出流
  • 在AndroidManifest配置文件中设置访问INTERNET的权限

GET方式:

if("https".equalsIgnoreCase(url.getProtocol())){
   ((HttpsURLConnection) connection).setSSLSocketFactory(HttpsUtil.getSSLSocketFactory());
}
if (connection.getResponseCode() ==  HttpURLConnection.HTTP_OK){
    is = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null){
        response.append(line);
    }
    is.close();
    connection.disconnect();
    return response.toString();
}

POST方法

            URL url = new URL(urlPath);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(15000);
            connection.setRequestProperty("Connection","Keep-Alive");
            connection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36");
            connection.setDoInput(true);
            connection.setDoOutput(true);
            if ("https".equalsIgnoreCase(url.getProtocol())){
                ((HttpsURLConnection) connection).setSSLSocketFactory(HttpsUtil.getSSLSocketFactory());
            }
            connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Length",String.valueOf(data.length));
            OutputStream os = connection.getOutputStream();
            os.write(data);
            os.flush();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStream is = connection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null){
                    response.append(line);
                }
                is.close();
                connection.disconnect();
                return response.toString();
            }

Android常用的网络编程框架

OkHttp

配置

  • OkHttp支持Android 2.3及其以上版本,Java要求JDK7.1以上
  • 添加依赖:implementation ‘com.squareup.okhttp3:okhttp:4.2.1’
  • 添加权限:

基本用法

  • 新建一个OkHttpClient对象
  • 通过Request.Builder对象创建一个Request对象
  • 通过Request对象构造Call对象,调用enqueue()以异步的方式将call加入调度队列,等待request执行完成
  • 通过Call队象的Callback对象返回执行结果

Http Get同步请求

  • 当HTTP响应码位于200到300之间时,认为操作时成功的
  • response.body()返回一个ResponseBody对象,封装了HTTP响应的主体数据,它的string(方法将这些数据转换为字符串,另一个byteStream()方法则返回一个InputStream流
  • 注意事项
    1、需要独立的线程中执行网络操作
    2、对于超过1MB的响应body,应使用流的方式来处理body

Get异步请求

     private void get(String url){
        // 1. 构造Request
        Request request = new Request.Builder().url(url)
                .header("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36")
                .addHeader("Accept","application/json")
                .get()
                .method("GET",null)
                .build();

        // 2. 发送请求,并处理回调
        OkHttpClient client = HttpsUtil.handleSSLHandshakeByOkHttp();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull final IOException e) {
                Log.e(TAG, e.getMessage());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvResult1.setText("获取失败," + e.getMessage());
                    }
                });
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                if (response.isSuccessful()){
                    // 1. 获取响应主体的json字符串
                    String json = response.body().string();
                    // 2. 使用FastJson库解析json字符串
                    final Ip ip = JSON.parseObject(json,Ip.class);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // 3. 根据返回的code判断获取是否成功
                            if (ip.getCode() != 0){
                                tvResult1.setText("未获得数据");
                            }else {
                                // 4. 解析数据
                                IpData data = ip.getData();
                                tvResult1.setText(data.getIp() + "," + data.getArea());
                            }
                        }
                    });
                }else {
                    Log.d(TAG, response.body().string());
                }
            }
        });
    }

Http Header的读写

  • 当写请求头的时候,使用header(name,value)可以设置唯一的name、value。如果已经有值,旧的将被移除,然后添加新的。
  • 使用addHeader(name,value)可以添加多值(添加,不移除已有的)。

Post方式提交Multipar文件

    private void uploadImage(String url, final String fileName) {
        // 1. 创建请求主体RequestBody
        RequestBody fileBody = RequestBody.create(new File(fileName), MEDIA_TYPE_PNG);
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("title", "头像")
                .addFormDataPart("file", fileName, fileBody)
                .build();

        // 2. 创建请求
        Request request = new Request.Builder()
                .url(url)
                .header("Authorization", "Client-ID 4ff8b2fc6d5f339")
                .header("User-Agent", "NetworkDemo")
                .post(body)
                .build();

        // 3. 创建OkHttpClient对象,发送请求,并处理回调
        OkHttpClient client = HttpsUtil.handleSSLHandshakeByOkHttp();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.e(TAG, e.getMessage());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvResult1.setText(fileName + "上传失败");
                    }
                });
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull final Response response) throws IOException {
                final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvResult1.setText("上传成功," + str);
                    }
                });
            }
        });
    }

Post异步下载文件

    private void downFile(final String url, final String path) {
        // 1. 创建Requet对象
        Request request = new Request.Builder().url(url).build();
        // 2. 创建OkHttpClient对象,发送请求,并处理回调
        OkHttpClient client = HttpsUtil.handleSSLHandshakeByOkHttp();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                if (response.isSuccessful()) {
                    // 1. 获取下载文件的后缀名
                    String ext = url.substring(url.lastIndexOf(".") + 1);
                    // 2. 根据当前时间创建文件名,避免重名冲突
                    final String fileName = System.currentTimeMillis() + "." + ext;
                    // 3. 获取响应主体的字节流
                    InputStream is = response.body().byteStream();
                    // 4. 将文件写入path目录
                    writeFile(is, path, fileName);
                    // 5. 在界面给出提示信息
                    tvResult1.post(new Runnable() {
                        @Override
                        public void run() {
                            tvResult1.setText(fileName + "下载成功,存放在" + path);
                        }
                    });
                }
            }

            @Override
            public void onFailure(@NotNull Call call, @NotNull final IOException e) {
                Log.d(TAG, e.getMessage());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvResult1.setText("下载失败," + e.getMessage());
                    }
                });
            }
        });
    }
图片加载框架Glide
  • Glide是由Google开源的一个图片加载库,是快速高效的Android开源媒体管理和图像加载框架
  • 它将媒体解码、内存和磁盘缓存以及资源池包装成简易用的界面

添加依赖
implementation ‘com.github.bumptech.glide:glide:4.2.0’
annotationProcessor ‘com.github.bumptech.glide:compiler:4.2.0’
implementation ‘com.github.bumptech.glide:okhttp3-integration:4.2.0’

Glide集成OKHttp加载https图片

@GlideModule
public class OkHttpGlideModule extends AppGlideModule {
    public void registerComponents(@NonNull Context context,
                                   @NonNull Glide glide,
                                   @NonNull Registry registry){
        OkHttpClient client = HttpsUtil.handleSSLHandshakeByOkHttp();
        registry.replace(GlideUrl.class, InputStream.class,
                new OkHttpUrlLoader.Factory(client));


    }

}

JsonRequest的用法

  • JsonRequest是抽象类
  • 有两个直接子类:JsonObjectRequest和JsonArrayRequest

Volley加载网络图片
ImageRequest的构造方法接收6个参数

  • 第1个参数:图片的url地址
  • 第2个参数:图片请求成功的回调,将图片设置到ImageView
  • 第3、4个参数:指定允许的图片最大宽度和高度,如果指定则对图片进行压缩,指定为0则不会压缩
  • 第5个参数:指定图片的颜色属性
  • 第6个参数:图片请求失败的回调

ImageLoader开发步骤

  • 创建RequestQueue对象
  • 创建ImageLoader对象,ImageLoader的构造函数接收两个参数,第一个参数是RequestQueue对象,第二个参数是ImageCache对象
  • 获取ImageListener对象
  • 调用ImageLoader的get()方法加载网络上的图片,get()方法接收2个参数,第1个参数是图片的url地址,第2个参数是ImageListener对象

JSON概述

  • JSON:JavaScript Object Notation,最初是针对JavaScript而设计,能够很方便地在字符串和JavaScript对象中进行转换。后来成为了一种世界通用的数据交换标准,独立于具体的编程语言
  • 与XML相比,JSON语法简明,格式紧凑,易读易懂,数据传输能量小,在移动互联网时代,这些特点有着巨大的吸引力,因此,JSON成为了XML的替代者而被广泛应用。

Android处理JSON数据

Android内置:

  • JSONArray
  • JSONObject

将Json文档转换为JSONObject或JSonArray对象

Google提供:

  • Gson组件(开源)

将Json文档转换为Java对象

JSONObject

  • JSONObject是“Key-Value”集合
    1:Key:String类型
    2:Value:基本数据类型包装类(String,Boolean,Integer,Long,Double),JSONObject,JSONArray
  • JSONObject可以在嵌套JSONObject或JSONArray,构成一个多级嵌套结构

JSONArr代表一个JSON对象的集合,但其中也可以再放置另一个JSONArray,构成一种多层嵌套的结构。

创建JSON字符串
  • 当需要创建JSON字符串,new一个JSONObject或者JSONArray对象,使用它们的put系列方法向其中追加数据,根据实际情况组合装配出JSONObj或JSONArray对象
  • 完成对象的装配工作之后,调用JSONObject或JSONArray的toString()方法即可生成JSON字符串
FastJSON

导入依赖:implementation ‘com.alibaba:fastjson:1.1.71.android’

FastJSON的工作原理
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值