Android Kotlin Flow下载图片并回调进度和错误
Posted 安果移不动
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Kotlin Flow下载图片并回调进度和错误相关的知识,希望对你有一定的参考价值。
用到了依赖
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.fragment:fragment-ktx:1.5.2"
implementation "androidx.room:room-runtime:2.4.3"
implementation "androidx.room:room-ktx:2.4.3"
kapt "androidx.room:room-compiler:2.4.3"
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
implementation "androidx.navigation:navigation-ui-ktx:2.5.2"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
没用到的也有。。不做剔除了
权限
<uses-permission android:name="android.permission.INTERNET" />
下载核心类
package com.example.android_flow_practice.download
import com.example.android_flow_practice.utils.copyTo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import okhttp3.Dispatcher
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.io.IOException
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 responseBody ->
val total = responseBody.contentLength()
//文件读写操作
file.outputStream().use output ->
val input = responseBody.byteStream()
var emittedProgress = 0L
input.copyTo(output) bytes ->
val progress = bytes * 100 / total
if (progress - emittedProgress > 5)
delay(100)
emit(DownLoadStatus.Progress(progress.toInt()))
emittedProgress = progress;
emit(DownLoadStatus.Done(file))
else
throw IOException(response.toString())
.catch
file.delete()
emit(DownLoadStatus.Error(it))
.flowOn(Dispatchers.IO)
核心类用到了一个
DownLoadStatus 的密封类
package com.example.android_flow_practice.download
import java.io.File
//密封类 成员都是他的子类
sealed class DownLoadStatus
object None : DownLoadStatus()
data class Progress(val value: Int) : DownLoadStatus()
data class Error(val throwable: Throwable) : DownLoadStatus()
data class Done(val file: File) : DownLoadStatus()
用到了一个下载帮助类
IOExt.kt
package com.example.android_flow_practice.utils
import java.io.InputStream
import java.io.OutputStream
inline fun InputStream.copyTo(
out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE, progress: (value: Long) -> Unit
): Long
var btyesCopied: Long = 0
val buffer = ByteArray(bufferSize)
var bytes = read(buffer)
while (bytes >= 0)
out.write(buffer, 0, bytes)
btyesCopied += bytes
bytes = read(buffer)
progress(btyesCopied)
return btyesCopied;
那其实代码布局也可以放进来
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context=".fragment.HomeFragment">
<ProgressBar
android:id="@+id/progressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:max="100" />
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/progressBar"
android:layout_centerHorizontal="true"
android:textSize="20sp"
tools:text="10%"
/>
</RelativeLayout>
下载对应的代码
package com.example.android_flow_practice.fragment
class DownloadFragment : Fragment()
private val mBinding: FragmentDownloadBinding by lazy
FragmentDownloadBinding.inflate(layoutInflater)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View?
// Inflate the layout for this fragment
return mBinding.root
private val TAG = "DownloadFragment"
override fun onActivityCreated(savedInstanceState: Bundle?)
super.onActivityCreated(savedInstanceState)
lifecycleScope.launchWhenCreated
context?.apply
val url = "https://www.xxx.com/xxx.png"
val path = getExternalFilesDir(null)?.path
Log.e(TAG, "path $path")
val file = File(path, "pic.png")
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(TAG, "下载错误")
这里下了一个图片并存放到sd卡当中
图片网络地址你们替换下吧
以上是关于Android Kotlin Flow下载图片并回调进度和错误的主要内容,如果未能解决你的问题,请参考以下文章
Android Kotlin Paging3 Flow完整教程
Android SingleLiveEvent Redux with Kotlin Flow
Kotlin 协程Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )