您的位置:

使用OkHttp下载文件

OkHttp是一个非常流行的HTTP客户端库,它提供了简单易用的API来完成网络请求,支持同步和异步请求,并且支持多种协议。OkHttp不仅可以用来请求JSON数据、图片等,还可以用来下载文件。下面我们将详细阐述如何使用OkHttp来下载文件。

一、Retrofit下载文件

在开始使用OkHttp下载文件之前,我们需要先了解如何使用Retrofit进行文件下载。

Retrofit是一个非常强大的网络库,它可以帮助我们快速构建RESTful的API,同时也提供了易用的文件下载API。在Retrofit中,我们可以使用@Streaming注解来下载大文件,并且可以在下载的过程中实时的更新进度。下面是一个使用Retrofit下载文件的示例:


@GET("file/download")
@Streaming
fun downloadFile(@Query("fileName") fileName: String): Call
   

   

首先定义了一个GET请求,请求路径为file/download,并且使用@Streaming注解来指定下载为流模式。同时,我们还需要定义一个ResponseBody类型的返回值。

接下来,我们就可以在Activity中使用Retrofit来下载文件了:


val call = retrofit.create(fileApi::class.java).downloadFile(fileName)
call.enqueue(object : Callback
    {
    override fun onResponse(call: Call
    , response: Response
     ) {
        if (response.isSuccessful) {
            val inputStream = response.body()?.byteStream()
            val file = File("文件路径")
            val outputStream = FileOutputStream(file)
            inputStream?.copyTo(outputStream, 1024)
            outputStream.flush()
            outputStream.close()
            inputStream?.close()
        }
    }

    override fun onFailure(call: Call
      , t: Throwable) {
        t.printStackTrace()
    }
})

      
     
    
   

在Activity中,我们首先定义了一个Retrofit的接口对象,并调用downloadFile方法开始下载文件。在onResponse回调中,我们可以拿到ResponseBody并将其转化为InputStream,最后将文件写入磁盘即可。在onFailure回调中,我们可以处理下载文件失败的情况。

二、OkHttp异步下载文件

使用OkHttp异步下载文件非常简单,我们可以直接使用OkHttpClient实例来创建一个Request请求,并使用enqueue方法来异步执行请求。下面是一个使用OkHttp异步下载文件的示例:


val client = OkHttpClient()
val request = Request.Builder().url("下载链接").build()
client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
      e.printStackTrace()
    }

    override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
            val inputStream = response.body()?.byteStream()
            val file = File("文件路径")
            val outputStream = FileOutputStream(file)
            inputStream?.copyTo(outputStream, 1024)
            outputStream.flush()
            outputStream.close()
            inputStream?.close()
        }
    }
})

在上述代码中,我们首先定义了一个OkHttpClient实例和一个Request实例,并调用enqueue方法来异步执行请求。在onFailure回调中,我们可以处理下载文件失败的情况,在onResponse回调中,则可以拿到ResponseBody并将其转化为InputStream,最后将文件写入磁盘即可。

三、OkHttp同步下载文件

使用OkHttp同步下载文件同样也非常简单,我们可以直接使用OkHttpClient实例来创建一个Request请求,并使用execute方法来同步执行请求。下面是一个使用OkHttp同步下载文件的示例:


val client = OkHttpClient()
val request = Request.Builder().url("下载链接").build()
val response: Response = client.newCall(request).execute()
if (response.isSuccessful) {
    val inputStream = response.body()?.byteStream()
    val file = File("文件路径")
    val outputStream = FileOutputStream(file)
    inputStream?.copyTo(outputStream, 1024)
    outputStream.flush()
    outputStream.close()
    inputStream?.close()
}

在上述代码中,我们同样也是先定义了一个OkHttpClient实例和一个Request实例,并调用execute方法来同步执行请求。如果请求成功,则可以拿到ResponseBody并将其转化为InputStream,最后将文件写入磁盘即可。

四、OkHttp配置下载进度回调

除了下载文件之外,有时候我们还需要实时获取下载进度。OkHttp提供了DownloadProgressInterceptor拦截器类,我们可以使用这个类来监听下载进度,以及在合适的时候更新进度条。下面是一个使用OkHttp配置下载进度回调的示例:


val listener = object : DownloadProgressListener {
    override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
        val progress = (100 * bytesRead / contentLength).toInt()
        // 更新进度条
    }
}
val client = OkHttpClient.Builder()
    .addInterceptor(DownloadProgressInterceptor(listener))
    .build()
val request = Request.Builder().url("下载链接").build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
    val inputStream = response.body()?.byteStream()
    val file = File("文件路径")
    val outputStream = FileOutputStream(file)
    inputStream?.copyTo(outputStream, 1024)
    outputStream.flush()
    outputStream.close()
    inputStream?.close()
}

在上述代码中,我们首先定义了一个DownloadProgressListener监听器类,并实现了update方法来更新进度条。接着,我们将DownloadProgressInterceptor拦截器类添加到OkHttpClient实例中,在下载过程中,DownloadProgressInterceptor会自动回调DownloadProgressListener的update方法来更新下载进度。

五、使用OkHttp下载Okok软件


val listener = object : DownloadProgressListener {
    override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
        val progress = (100 * bytesRead / contentLength).toInt()
        Log.d("TAG", "progress: $progress")
    }
}

val url = "https://dldir1.qq.com/weixin/android/weixin7016android1720.apk"
val client = OkHttpClient.Builder()
    .addInterceptor(DownloadProgressInterceptor(listener))
    .build()
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
    val inputStream = response.body()?.byteStream()
    val file = File(context.externalCacheDir, "okok.apk")
    val outputStream = FileOutputStream(file)
    inputStream?.copyTo(outputStream, 1024)
    outputStream.flush()
    outputStream.close()
    inputStream?.close()
    // 使用系统自带的安装器安装APK
    val intent = Intent(Intent.ACTION_VIEW)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        val contentUri = FileProvider.getUriForFile(context, "${context.packageName}.fileProvider", file)
        intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
    } else {
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        intent.setDataAndType(Uri.parse("file://${file.absolutePath}"), "application/vnd.android.package-archive")
    }
    context.startActivity(intent)
}

在上述代码中,我们首先定义了一个DownloadProgressListener监听器类,并实现了update方法来更新进度条。接着,我们使用OkHttpClient异步下载APK文件,同时也添加了DownloadProgressInterceptor拦截器类,来回调DownloadProgressListener的update方法更新下载进度。在下载完成后,我们将APK文件写入磁盘,并使用系统自带的安装器进行安装。