前言:kotlin挂起函数+ViewModel,使异步如此简单。
案例:(1)下载文件(2)保存文件
viewModelScope.launch {
kotlin.runCatching {
//下载文件
HomeRespository().downFile(billLogoUrl)
}.onSuccess {
kotlin.runCatching {
//保存文件
val fileName = billLogoUrl.substring(billLogoUrl.lastIndexOf("/"))
FileUtil.saveFile(it.byteStream(), FileUtil.PATH, fileName)
}.onSuccess {
AppPrefsUtils.putBoolean(AppPrefsUtils.BILL_LOGO_DOWN_SUCCESS, true)
}.onFailure {
AppPrefsUtils.putBoolean(AppPrefsUtils.BILL_LOGO_DOWN_SUCCESS, false)
}
}.onFailure {
AppPrefsUtils.putBoolean(AppPrefsUtils.BILL_LOGO_DOWN_SUCCESS, false)
}
}
class HomeRespository {
private val mService = RetrofitFactory.instance.create(BaseConstant.SERVICE_HOST).create(
HomeApi::class.java
)
suspend fun downFile(url: String): ResponseBody {
return mService.downFile(url)
}
}
interface HomeApi {
@Streaming
@GET
suspend fun downFile(@Url url: String): ResponseBody
}
object FileUtil {
val PATH = "Demo/take"
suspend fun saveFile(inputStream: InputStream, path: String, fileName: String) = withContext(Dispatchers.IO){
val buff = ByteArray(4096)
val folder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
BaseApplication.context.filesDir
} else {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
}
val dir = File(folder, path)
if (!dir.exists()){
dir.mkdirs()
}
val file = File(dir, fileName)
if (file.exists()) {
file.delete()
}
file.createNewFile()
val output = FileOutputStream(file)
var readed = inputStream.read(buff)
while (readed != -1) {
output.write(buff, 0, readed)
readed = inputStream.read(buff)
}
output.flush()
output.close()
inputStream.close()
}
}
注:
(1)下载文件:由Retrofit支持挂起函数,只需将fun前加上suspend即可
(2)保存文件:通过withContext(Dispatchers.IO)和suspend来实现异步耗时任务
(3)viewModelScope默认是主线程,只是挂起fun在子线程执行,onSuccess和onFailure均在viewModelScope线程即主线程
(4)suspend声明fun为挂起函数,该函数可以调用挂起函数或者通过withContext(Dispatchers.IO)实现具体操作,如果仅仅是普通的fun前加suspend是无效的仍为普通fun