IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin 协程+flow 下载案例 -> 正文阅读

[移动开发]Kotlin 协程+flow 下载案例

//扩展方法 读写文件并返回,下载进度
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
}

sealed class DownloadStatus{
     data class Progress(val value:Int):DownloadStatus() //返回下载进度
     data class Error(val throwable: Throwable):DownloadStatus() //返回失败错误
     data class Done(val file: File):DownloadStatus() //返回结果
}

此类为枚举类,启得是封装的作用

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() //使用OKHttp来进行网络请求
            if (response.isSuccessful) { //是否请求成功
                response.body()!!.let { body ->
                    val contentLength = body.contentLength()//下载内容总长度

                    file.outputStream().use { output ->
                        val input = body.byteStream()
                        var emittedProcess = 0L
                        input.copyTo(output) { bytesCopied ->
                            val progress = bytesCopied * 100 / contentLength //计算下载进度
                            if (progress - emittedProcess > 5) {
                                delay(100)
                                emit(DownloadStatus.Progress(progress.toInt()))//发送下载进度
                                emittedProcess=progress
                            }
                        }
                    }
                }
                emit(DownloadStatus.Done(file)) //返回结果
            } else {
                throw  IOException(response.toString()) //没有请求成功抛出异常
            }
        }.catch {
            file.delete()//发生异常 删除错误文件
            emit(DownloadStatus.Error(it))//并返回错误
        }.flowOn(Dispatchers.IO)//切换子线程
    }
}

单例类,封装下载代码。

class Fragmentb : Fragment() {
        val url:String="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fclubimg.club.vmall.com%2Fdata%2Fattachment%2Fforum%2F202005%2F15%2F230954fsa0bsgqep8zu2j9.jpg&refer=http%3A%2F%2Fclubimg.club.vmall.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637312693&t=4d8c9a64de10cb68fb26d027a0ee4225"
    private val mBinding: FragmentFragmentbBinding by lazy {
        FragmentFragmentbBinding.inflate(layoutInflater)
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return mBinding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
                //这个协程和fragment的生命周期绑定
        lifecycleScope.launchWhenCreated {
        context?.apply {
                            // 外部文件目录路径
            val file=File(getExternalFilesDir(null)?.path,"pic.jpg")

              DownloadManager.download(url,file).collect {
                status->
                  when(status){
                      is DownloadStatus.Progress->{  //下载进度
                          mBinding.apply {
                              progressBar.progress=status.value
                              tvProgress.text="${status.value}%"
                          }
                      }
                      is DownloadStatus.Error->{  //下载出错
                          Toast.makeText(context,"下载错误",Toast.LENGTH_SHORT).show()
                      }
                      is DownloadStatus.Done->{  //下载完成
                          mBinding.apply {
                              progressBar.progress=100
                              tvProgress.text="100&"
                          }
                          Toast.makeText(context,"下载完成",Toast.LENGTH_SHORT).show()
                      }else->{
                            Log.d("ning","下载失败")
                      }
                  }
              }
          }
        }
    }
}

在fragment中引用并给UI反馈。

效果演示:

?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-24 15:24:46  更:2022-02-24 15:25:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年9日历 -2024/9/20 9:04:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码