美文网首页
kotlin--Flow文件下载

kotlin--Flow文件下载

作者: aruba | 来源:发表于2021-09-19 15:34 被阅读0次

    学习了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.download
    
    import 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.download
    
    import 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 * 100
                                emit(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.utils
    
    import java.io.InputStream
    import java.io.OutputStream
    
    inline fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE, progress: (Long)-> Unit): Long {
        var bytesCopied: Long = 0
        val buffer = ByteArray(bufferSize)
        var bytes = read(buffer)
        while (bytes >= 0) {
            out.write(buffer, 0, bytes)
            bytesCopied += bytes
            bytes = read(buffer)
    
            progress(bytesCopied)
        }
        return bytesCopied
    }
    
    
    2.定义ViewModel

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

    package com.aruba.flowapplyapplication.viewmodel
    
    import 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 = progressData
    
        private val url: String = "http://10.254.219.178:8080/test.rar"
    
        fun downloadClick(v: View) {
            viewModelScope.launch {
                progressData.value = 0
                val 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 = 100
                            Toast.makeText(context, "下载完成", Toast.LENGTH_SHORT).show()
                        }
                        is DownloadStatus.Err ->
                            Toast.makeText(context, it.toString(), Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
    }
    
    3.DataBinding和ViewModel绑定
    package com.aruba.flowapplyapplication
    
    import 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.DownloadViewModel
    
    class 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 = downloadViewModel
            fragmentFlowDownBinding.lifecycleOwner = this;
    
            return fragmentFlowDownBinding.root
        }
    
    }
    

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

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

    相关文章

      网友评论

          本文标题:kotlin--Flow文件下载

          本文链接:https://www.haomeiwen.com/subject/srmugltx.html