Retrofit Service
@Streaming @GET fun downloadFile(@Url fileUrl: String): Call<ResponseBody>
|
这里不能用suspend
关键字
@Streaming
注解: 这个注解告知 Retrofit 不应将整个响应主体加载到内存中。它用于处理大文件或者流式数据,允许以流的方式逐段处理响应数据而不是一次性加载全部到内存中。它通常在下载大文件或者处理视频流等情况下使用。
suspend
关键字: 这是 Kotlin 协程的一部分,用于标记函数可以挂起执行。它允许在协程中使用挂起函数,使得异步操作更加方便和易于处理。
因为它们的作用和机制不同,@Streaming
注解主要是为了告知 Retrofit 应该以流的方式处理响应数据,而 suspend
关键字用于标记可以挂起执行的函数。@Streaming
注解主要作用于 Retrofit 处理响应体的方式,而 suspend
关键字主要用于在协程中处理异步操作。
在 Retrofit 中,@Streaming
注解通常与 Call<ResponseBody>
结合使用,因为它们允许以流式方式处理响应体。而 suspend
关键字用于将 Retrofit 方法转换为可以在协程中使用的挂起函数,但由于其异步性质,与 @Streaming
注解在技术上并不兼容。
Retrofit创建
fun create(): FileDownloadService { val okHttpClient = OkHttpClient.Builder().build() val retrofit = Retrofit.Builder() .baseUrl("http://218.77.59.2:6203/") .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build() return retrofit.create(FileDownloadService::class.java) }
|
ViewModel中使用
fun download() { viewModelScope.launch(Dispatchers.IO) { try { val response = withContext(Dispatchers.IO) { fileDownloadService.downloadFile(MainActivity.DOWNLOAD_URL).execute() }
if (response.isSuccessful) { val body = response.body() if (body != null) { val url = response.raw().request().url().toString() val fileName = getFileNameFromUrl(url) saveFile(body, fileName) } } else { LogUtils.d("文件处理失败: ${response.isSuccessful}}") } }catch (e: Exception) { e.printStackTrace() } } }
private fun saveFile(body: ResponseBody,fileName: String?) { var inputStream: InputStream? = null var outputStream: OutputStream? = null
try { val fileReader = ByteArray(4096) val fileSize = body.contentLength() val fileSizeDownloaded: Long = 0 inputStream = body.byteStream() val file = File(application.filesDir,fileName?:"a.apk") LogUtils.d("保存文件位置: ${file.absolutePath}") outputStream = FileOutputStream(file)
while (true) { val read = inputStream.read(fileReader) if (read == -1) { break } outputStream.write(fileReader, 0, read) } outputStream.flush()
val fileMD5 = FileUtils.getFileMD5ToString(file) LogUtils.d("保存成功,${fileMD5}") } catch (e: IOException) { e.printStackTrace() } finally { inputStream?.close() outputStream?.close() } }
private fun getFileNameFromUrl(url: String): String? { var fileName: String? = null val lastPathSegment = Uri.parse(url).lastPathSegment if (!lastPathSegment.isNullOrEmpty()) { fileName = lastPathSegment } return fileName }
|