当前位置: 代码迷 >> 综合 >> kotlin--Flow文件下载
  详细解决方案

kotlin--Flow文件下载

热度:93   发布时间:2023-09-14 05:33:18.0

学习了kotlin后,我们将它运用到实际开发中,结合Flow实现文件下载

最终效果:

kotlin--Flow文件下载
项目使用了Navigation框架:Activity+Fragment的方式

导入依赖:

implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'implementation 'androidx.legacy:legacy-support-v4:1.0.0'//依赖协程核心库 ,提供Android UI调度器implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1"//依赖当前平台所对应的平台库 (必须)implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1'implementation 'com.squareup.retrofit2:retrofit:2.9.0'

并启用DataBinding

dataBinding {enabled = true}

fragment的创建、Navigation Graph的连接等操作就不介绍了

1.首先实现下载工具类,包含状态和下载实现

使用密封类定义状态:

package com.aruba.flowapplyapplication.downloadimport java.io.File/*** 下载状态* Created by aruba on 2021/9/19.*/
sealed class DownloadStatus {data class Progress(val progress: Int) : DownloadStatus()data class Err(val t: Throwable) : DownloadStatus()data class Done(val file: File) : DownloadStatus()
}

静态方法方式定义下载管理类:

package com.aruba.flowapplyapplication.downloadimport kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import com.dongnaoedu.flowpractice.utils.copyTo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import okhttp3.Dispatcher
import java.io.IOException/*** Created by aruba on 2021/9/19.*/
object DownloadManager {fun download(url: String, file: File): Flow<DownloadStatus> {return flow {val request = Request.Builder().url(url).get().build();val response = OkHttpClient.Builder().build().newCall(request).execute()if (response.isSuccessful) {response.body()!!.let { body ->//文件大小val totalLength = body.contentLength().toDouble()//写文件file.outputStream().run {val input = body.byteStream()input.copyTo(this) { currentLength ->//当前下载进度val process = currentLength / totalLength * 100emit(DownloadStatus.Progress(process.toInt()))}}emit(DownloadStatus.Done(file))}} else {throw IOException(response.toString())}}.catch {file.delete()emit(DownloadStatus.Err(it))}.flowOn(Dispatchers.IO)}
}

InputStream添加扩展函数实现字节拷贝

package com.dongnaoedu.flowpractice.utilsimport java.io.InputStream
import java.io.OutputStreaminline fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE, progress: (Long)-> Unit): Long {var bytesCopied: Long = 0val buffer = ByteArray(bufferSize)var bytes = read(buffer)while (bytes >= 0) {out.write(buffer, 0, bytes)bytesCopied += bytesbytes = read(buffer)progress(bytesCopied)}return bytesCopied
}
2.定义ViewModel

使用LiveData定义进度属性,并实现下载按钮的点击事件,由于Flow的collect函数为挂起函数,需要使用协程作用域,我们直接使用viewModelScope

package com.aruba.flowapplyapplication.viewmodelimport android.app.Application
import android.content.Context
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.lifecycle.*
import com.aruba.flowapplyapplication.download.DownloadManager
import com.aruba.flowapplyapplication.download.DownloadStatus
import com.aruba.flowapplyapplication.download.DownloadStatus.Progress
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import java.io.File/*** Created by aruba on 2021/9/19.*/
class DownloadViewModel(val context: Application) : AndroidViewModel(context) {private var progressData = MutableLiveData<Int>()val progress = progressDataprivate val url: String = "http://10.254.219.178:8080/test.rar"fun downloadClick(v: View) {viewModelScope.launch {progressData.value = 0val file = File(context.getExternalFilesDir(null), "test.rar")DownloadManager.download(url, file).collect {when (it) {is Progress -> {Log.i("progress", "progress: $it.progress")progressData.value = it.progress}is DownloadStatus.Done -> {progressData.value = 100Toast.makeText(context, "下载完成", Toast.LENGTH_SHORT).show()}is DownloadStatus.Err ->Toast.makeText(context, it.toString(), Toast.LENGTH_SHORT).show()}}}}
}
3.DataBinding和ViewModel绑定
package com.aruba.flowapplyapplicationimport android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.aruba.flowapplyapplication.databinding.FragmentFlowDownBinding
import com.aruba.flowapplyapplication.viewmodel.DownloadViewModelclass FlowDownloadFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {val fragmentFlowDownBinding = DataBindingUtil.inflate<FragmentFlowDownBinding>(layoutInflater,R.layout.fragment_flow_down,container,false)val downloadViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory(requireActivity().application)).get(DownloadViewModel::class.java)fragmentFlowDownBinding.downloadViewModel = downloadViewModelfragmentFlowDownBinding.lifecycleOwner = this;return fragmentFlowDownBinding.root}}

文件下载就完成了,代码量相比Java可以自行感受下

Demo地址:https://gitee.com/aruba/flow-apply-application.git