Android 网络通信 | 青训营笔记

114 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第6天

一、前言

今天学习到的是Android的网络通信部分,对于这一部分的学习我根据今日学习的内容加入自己的一个Demo为例,加深对本节课知识点的掌握。

今日份的边学边练中,网络通信模块以本文的学习制作了一个Retrofit的Demo:

实现效果如图所示:

在Retrofit页面中

截屏2022-07-28 13.02.35.png 点击获取API的button

截屏2022-07-28 13.04.14.png

PS:这里获取的API接口是课件资料中的www.bytedance.com/users/{uid}… 其中{uid}要替换为实际的uid,最终请求为www.bytedance.com/users/1123/…

截屏2022-07-28 13.04.48.png

核心代码与注释在文章中会有说明;

二、本节课知识点大纲:

1. Android 网络通信

1.1.网络请求

1.2 使用举例

1.2.1 使用介绍

1.3 总结

三、Android 网络通信:

网络请求

  • 客户端向服务端发起请求,服务端返回数据给到客户端
  • 由于网络请求在大型App里使用非常频繁,为了更好的支持业务迭代,一般会进行网络请求的封装

网络框架对比

image.png

说明:

  • Volley的Request和Response都是把数据方法放到byte[]数组里,不支持输入输出流,把数据放到数组中,如果大文件多了,数组就会非常大且多,消耗内存
  • 行业内,目前基本上都是Retrofit 和 OkHttp组合的这种方式来进行网络请求
  • IO 和 NIO这两个都是Java中的概念,如果我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我,然后再处理回调。而第二种就是 NIO 的方式,非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理数据流的一个库。

总结:

  • 目前Retrofit和OkHttp的组合,功能更加全面,封装更加彻底,当下最为流行的网络请求方式,我们本文也会重点来关注Retrofit的使用和原理的介绍。

Retrofit的使用介绍

Retrofit其实是对OkHttp的一个封装,也是当前最为流行的一种网络请求组合方式。

Retrofit的使用举例

场景假设:客户端知道了一个用户的uid,想通过服务端查下这个用户的姓名,通过Retrofit如何实现呢? 接口:www.bytedance.com/users/{uid}… 其中{uid}要替换为实际的uid,例如1123,最终请求为www.bytedance.com/users/1123/…

image.png

  • 添加Retrofit库的依赖

    • 在需要用到Retrofit接口的module中,新增依赖(最新的版本可看GitHub
dependencies {
    //Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'

    implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
}
  • 创建 用于描述网络请求API的接口

API Service

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;

public interface ApiService {

    @GET("/users/{uid}/name")
    Call<ResponseBody> getResponse();
}
import com.example.jere.retrofit.practiceDemo.ApiWrapperBase;

/**
 * @author jere
 * @date 12/12/2018
 */
public class ApiWrapper extends ApiWrapperBase {
    protected ApiWrapper() {
        super();
        mService = mRetrofit.create(ApiService.class);
    }

    public static ApiWrapper newInstance() {
        return new ApiWrapper();
    }

    @Override
    public ApiService getService() {
        return (ApiService) mService;
    }


    @Override
    protected String getApiHost() {
        return "https://www.bytedance.com";
    }
}
  • 发起网络请求
public Object getService() {
        return mService;
    }

    @NonNull
    protected OkHttpClient createClient() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(BASIC);
        return baseHttpClientBuilder()
                .hostnameVerifier((hostname, session) -> true)
                .addInterceptor(logging)
                .build();
    }


    protected OkHttpClient.Builder baseHttpClientBuilder() {
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
                .connectTimeout(VALUE_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(VALUE_WRITE_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(VALUE_READ_TIMEOUT, TimeUnit.SECONDS);

        // Create a trust manager that does not validate certificate chains
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                try {
                    chain[0].checkValidity();
                } catch (Exception e) {
                    throw new CertificateException("Certificate not valid or trusted");
                }
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }
        };

        // Install the all-trusting trust manager
        try {
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, new TrustManager[]{trustManager}, null);
            clientBuilder.sslSocketFactory(new CustomTLSSocketFactory(sslContext.getSocketFactory()), trustManager);

            ConnectionSpec cs11 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_1)
                    .build();
            ConnectionSpec cs12 = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();

            List<ConnectionSpec> specs = new ArrayList<>();
            specs.add(cs11);
            specs.add(cs12);

            clientBuilder.connectionSpecs(specs);

        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            Log.d("FairProductDiyApiHelper", e.getMessage());
        }
        return clientBuilder;
    }

}

实现效果如下: 截屏2022-07-28 13.02.35.png 点击获取API的button

截屏2022-07-28 13.04.14.png

截屏2022-07-28 13.04.48.png

总结

  • 引入依赖库
  • 创建 用于描述网络请求 的接口
  • 发起网络请求

    • 创建Retrofit实例
    • 创建iUserInfoService实例
    • 创建网络请求Call对象
    • 使用Call对象发起异步请求

四、课外补充:

Retrofit基本用法

最好用的网络库:Retrofit。它和OkHttp的定位完全不同,OkHttp侧重的是底层通信的实现,而Retrofit侧重的是上层接口的封装。

Retrofit就是Square公司在OkHttp的基础上进一步开发出来的应用层网络通信库,使得我们可以用更加面向对象的思维进行网络操作。

Retrofit的基本设计思想

同一款应用程序中所发起的网络请求绝大多数指向的是同一个服务器域名。

服务器提供的接口通常是可以根据功能来归类的。将服务器接口合理归类能够让代码结构变得更加合理,从而提高可阅读性和可维护性。

开发者更加习惯于“调用一个接口,获取它的返回值”这样的编码方式,其实大多数人并不关心网络的具体通信细节,但是传统网络库的用法却需要编写太多网络相关的代码。

而Retrofit的用法就是基于以上几点来设计的。

首先我们可以配置好一个根路径,然后在指定服务器接口地址时只需要使用相对路径即可,这样就不用每次都指出完成的URL地址了。

另外,Retrofit允许我们对服务器接口进行归类,就功能同属一类的服务器接口定义到同一个接口文件中。

最后,我们也完全不用关心网络通信的细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。

当我们在程序中调用该方法时,Retrofit会自动向对应的服务器接口发起请求,并将相应的数据解析成返回值声明的类型。这就使得我们可以用更加面向对象的思维来进行网络操作。

五、引用参考:

课外补充引用:

文章学习来源:

感谢以上作者的文章,今天的学习收获满满!!Thanks and HappyCoding!