Bootstrap

Android开发实战班 -网络编程 - Retrofit 网络请求 + OkHttp 使用详解

在现代 Android 应用开发中,网络编程是必不可少的一部分。Retrofit 是 Square 公司推出的一款类型安全的 HTTP 客户端库,简化了与 RESTful API 的交互。Retrofit 基于 OkHttp,并提供了简洁的接口定义和强大的功能,如异步请求、请求拦截、JSON 解析等。本章节将深入讲解 Retrofit 的基本概念、配置、使用方法以及与 OkHttp 的结合,帮助学员掌握 Retrofit 网络请求的实现。

19.1 网络编程概述

  • 网络编程的作用:

    • 网络编程用于实现应用与服务器之间的数据交互,例如获取数据、提交数据、更新数据等。
    • 常见的网络请求类型有 GET, POST, PUT, DELETE 等。
  • 网络编程的挑战:

    • 异步操作: 网络请求是异步的,需要处理线程切换和回调。
    • 错误处理: 需要处理网络错误、超时、数据解析错误等。
    • 安全性: 需要处理 HTTPS、证书验证、加密传输等。
    • 性能优化: 需要优化网络请求的性能,例如缓存、重试机制等。

19.2 Retrofit 简介

  • Retrofit 的历史与发展:

    • Retrofit 是 Square 公司于 2013 年推出的 HTTP 客户端库。
    • Retrofit 基于 OkHttp,提供了更简洁的接口定义和更强大的功能。
    • Retrofit 2.0 于 2016 年发布,引入了对协程的支持。
  • Retrofit 的优势:

    • 类型安全: Retrofit 使用接口定义 API,提供了类型安全的请求和响应。
    • 简洁易用: Retrofit 提供了简洁的 API,易于上手和使用。
    • 强大的功能: Retrofit 支持异步请求、请求拦截、JSON 解析、文件上传下载等。
    • 可扩展性: Retrofit 可以与 OkHttp 拦截器、转换器等结合使用,实现更强大的功能。
    • 协程支持: Retrofit 2.6.0 及以上版本支持 Kotlin 协程,简化异步请求代码。

19.3 Retrofit 的基本使用

19.3.1 添加 Retrofit 依赖

build.gradle 文件中添加 Retrofit 依赖:

dependencies {
    implementation "com.squareup.retrofit2:retrofit:2.9.0"
    implementation "com.squareup.retrofit2:converter-gson:2.9.0"
}
19.3.2 定义 API 接口

使用 Retrofit 的接口定义 API,例如定义一个 GitHub API 接口:

import retrofit2.http.GET
import retrofit2.http.Path

interface GitHubService {
    @GET("users/{user}/repos")
    suspend fun listRepos(@Path("user") user: String): List<Repo>
}

data class Repo(
    val id: Int,
    @field:SerializedName("name") val name: String,
    @field:SerializedName("html_url") val url: String
)
19.3.3 创建 Retrofit 实例

使用 Retrofit.Builder 创建 Retrofit 实例,并配置基础 URL 和转换器:

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val service = retrofit.create(GitHubService::class.java)
19.3.4 发起网络请求

使用 Retrofit 发起网络请求,例如获取用户仓库列表:

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

CoroutineScope(Dispatchers.IO).launch {
    try {
        val repos = service.listRepos("octocat")
        // 处理数据
    } catch (e: Exception) {
        // 处理错误
    }
}

19.4 Retrofit 与 OkHttp 的结合

Retrofit 基于 OkHttp,提供了更强大的功能,例如请求拦截、缓存、重试机制等。

19.4.1 使用 OkHttp Interceptor

OkHttp Interceptor 可以在请求发送前或响应返回后拦截请求和响应,进行自定义处理,例如添加请求头、打印日志等。

  • 添加请求头:

    import okhttp3.Interceptor
    import okhttp3.OkHttpClient
    import okhttp3.Request
    import okhttp3.Response
    
    val headerInterceptor = Interceptor { chain ->
        val original: Request = chain.request()
        val requestBuilder = original.newBuilder()
            .header("Accept", "application/json")
            .method(original.method, original.body)
        val request: Request = requestBuilder.build()
        chain.proceed(request)
    }
    
    val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(headerInterceptor)
        .build()
    
    val retrofit = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    
  • 打印日志:

    import okhttp3.logging.HttpLoggingInterceptor
    
    val loggingInterceptor = HttpLoggingInterceptor()
    loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
    
    val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()
    
19.4.2 使用 OkHttp Cache

OkHttp 提供了缓存机制,可以缓存网络请求结果,提高应用性能。

  • 配置缓存:

    import okhttp3.Cache
    import java.io.File
    
    val cacheSize = 10 * 1024 * 1024 // 10 MB
    val cacheDirectory = File(context.cacheDir, "http-cache")
    val cache = Cache(cacheDirectory, cacheSize)
    
    val okHttpClient = OkHttpClient.Builder()
        .cache(cache)
        .build()
    
  • 配置缓存策略:

    import okhttp3.CacheControl
    
    val request = Request.Builder()
        .url("https://api.github.com/users/octocat/repos")
        .cacheControl(CacheControl.Builder()
            .maxStale(1, TimeUnit.DAYS)
            .build())
        .build()
    

19.5 Retrofit 进阶功能

19.5.1 文件上传与下载
  • 文件上传:

    @Multipart
    @POST("upload")
    suspend fun uploadFile(
        @Part file: MultipartBody.Part,
        @Part("description") description: RequestBody
    )
    
  • 文件下载:

    @GET
    suspend fun downloadFile(@Url fileUrl: String): ResponseBody
    
    // 下载文件
    val response = service.downloadFile("https://example.com/file.zip")
    val file = File(context.filesDir, "file.zip")
    response.body()?.byteStream()?.use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
    
19.5.2 错误处理
  • 自定义异常:
    class ApiException(message: String, val code: Int) : Exception(message)
    
    // 解析错误
    try {
        val response = service.getData()
        if (response.isSuccessful) {
            // 处理成功
        } else {
            throw ApiException("API Error", response.code())
        }
    } catch (e: ApiException) {
        // 处理 API 异常
    } catch (e: Exception) {
        // 处理其他异常
    }
    

19.6 实战案例

  1. 案例一:使用 Retrofit 实现 GitHub API 请求

    • 定义 GitHub API 接口。
    • 创建 Retrofit 实例。
    • 使用协程发起网络请求,获取用户仓库列表。
    • 在 Activity 中显示仓库列表。
  2. 案例二:使用 Retrofit 实现文件上传

    • 定义文件上传 API 接口。
    • 使用 Retrofit 上传文件。
    • 在 Activity 中选择文件并上传。
  3. 案例三:使用 Retrofit 实现文件下载

    • 定义文件下载 API 接口。
    • 使用 Retrofit 下载文件。
    • 在 Activity 中下载文件并保存到内部存储。

19.7 课后作业

  1. 任务一:使用 Retrofit 实现 GitHub API 请求

    • 定义 GitHub API 接口。
    • 创建 Retrofit 实例。
    • 使用协程发起网络请求,获取用户仓库列表。
    • 在 Activity 中显示仓库列表。
  2. 任务二:使用 Retrofit 实现文件上传

    • 定义文件上传 API 接口。
    • 创建 Retrofit 实例。
    • 使用协程发起文件上传请求。
    • 在 Activity 中选择文件并上传。
  3. 任务三:使用 Retrofit 实现文件下载

    • 定义文件下载 API 接口.
    • 创建 Retrofit 实例.
    • 使用协程发起文件下载请求.
    • 在 Activity 中下载文件并保存到内部存储.

通过本章节的学习,学员将能够掌握 Retrofit 网络请求的基本概念、使用方法以及与 OkHttp 的结合,并能够使用 Retrofit 实现各种网络请求操作,包括 GET, POST, 文件上传下载等。

;