最近在做Lottie动画,由于动画资源放到了assets中,导致apk的体积迅速增大,所以把lottie动画资源放到服务器,一启动应用就在子线程中默认下载这些资源,下载到app内存文件夹中,不需要申请权限,等到需要使用的时候,就可以从文件夹中加载了,这样可以减少apk的体积
使用方式:
object FileDownloadConstant {
const val filePath = "gifts/zip"
//下载下来的资源存放的根目录
var DEFAULT_FILE_CACHE_PATH = ContextUtils.getApplicationContext().getExternalFilesDir("gift").path
//礼物动画存储目录
var rootPathAnimation = "${DEFAULT_FILE_CACHE_PATH}/${filePath}"
object BaseConfig{
//资源存放的apk地址
const val ANIMATION_OSS_URL = "https://static.network.com"
const val GIFT_PATH = "${ANIMATION_OSS_URL}/${filePath}"
}
//资源列表
var giftList = listOf("xiagujian","chiji","kele","banzhuan","memeda","qiujiaowang","qiqiu","penghua",
"yanhua","meigui","feiji","chengbao","bixin","loveyou","sobuteful","hongchun","girlfri","huangguan",
"leihen","qiubite","haozhuchi","zhuguang","langman","bidong","dangao","laohu","mao","xiong","hunsha",
"dianzan","bangbangtang","icecream","yiwendingqing","haidao","iphone","yecanyuehui","lovetree","jiarilvxing")
}
复制代码
文件下载工具类
/**
* 文件下载工具类
*/
object FileDownloadUtil {
private val parentPath = FileDownloadConstant.rootPathAnimation
private val fetch = Fetch.getInstance(FetchConfiguration.Builder(ContextUtils.getApplicationContext())
.setLogger(FetchLogger(true,"动画下载"))
.enableLogging(true)
.setDownloadConcurrentLimit(5)
.setAutoRetryMaxAttempts(3)
.setHttpDownloader(OkHttpDownloader(Downloader.FileDownloaderType.PARALLEL))
.setProgressReportingInterval(1000)
.build())
/**
* 下载监听
*/
class DownloadListener(private val groupId : Int,private val num:Int,private val callback :((Boolean) -> Unit) ?) : AbstractFetchListener(){
private var downloaded: Int = 0 //已下载的数量
override fun onCompleted(download: Download) {
if (download.group != groupId) {
return
}
//资源打包成zip文件放到了服务器上,所以下载下来要解压缩
LottieAnimationUtils.unZip(download.file, parentPath)
downloadCount(true)
}
override fun onError(download: Download, error: Error, throwable: Throwable?) {
if (download.group != groupId) {
return
}
downloadCount(false)
}
private val downloadCount: (Boolean) -> Unit = {
downloaded++
if (downloaded == num) {
callback?.invoke(it)
fetch.removeListener(this)
}
}
}
fun downloadList(pathList: List<String>, priority: Priority = Priority.NORMAL, callback: ((Boolean) -> Unit)? = null) {
val groupId = Random.nextInt()
pathList.filter {
//本地文件不存在的才下载
!File(parentPath + File.separator + it).exists()
}.flatMap { path ->
arrayListOf(Request("${FileDownloadConstant.BaseConfig.GIFT_PATH}/$path" + ".zip", parentPath + "/" + path + ".zip").also {
it.groupId = groupId
it.priority = priority
})
}.apply {
if (size == 0) {
callback?.invoke(true)
return@apply
}
fetch.addListener(DownloadListener(groupId, size, callback)).enqueue(this)
}
}
/**
* 下载单个文件
*/
fun download(path: String, callback: ((Boolean) -> Unit)? = null) {
if (File("$parentPath/$path" + ".zip").exists()) {
callback?.invoke(true)
return
}
val groupId = Random.nextInt()
fetch.addListener(DownloadListener(groupId, 1, callback)).enqueue(Request("${FileDownloadConstant.BaseConfig.GIFT_PATH}/$path" + ".zip", "$parentPath/$path.zip").also { it.groupId = groupId })
}
}
复制代码
下载框架使用的是一个开源的,名字叫Fetch
在启动页的onCreate方法中,调用:
FileDownloadUtil.INSTANCE.downloadList(FileDownloadConstant.INSTANCE.getGiftList(), Priority.NORMAL,null);
复制代码
就开始下载资源了
那么怎么使用Lottie框架加载文件夹中的动画资源呢?直接上代码
object LottieAnimationUtils {
//lottie加载本地资源的核心方法
fun loadLottie(lottieAnimationView: LottieAnimationView,imagePath:String,dataPath : String,giftName:String):FileInputStream?{
lottieAnimationView.setCacheComposition(false)
val imageFiles = File(imagePath)
val jsonFile = File(dataPath)
var fis:FileInputStream? = null
//资源中只有json文件的时候走这里
if (!imageFiles.exists()) {
if (jsonFile.exists()) {
fis = FileInputStream(jsonFile)
try {
lottieAnimationView.setImageAssetDelegate(null)
}catch (e : Exception) {
}
LottieComposition.Factory.fromInputStream(fis) {
lottieAnimationView.postDelayed(Runnable {
lottieAnimationView.visibility = View.VISIBLE
},200)
it?.let {
it1 -> lottieAnimationView.setComposition(it1)
}
lottieAnimationView.playAnimation()
}
}else {
FileDownloadUtil.download(giftName)
}
return fis
}
//资源中有imges和json的走这里
try {
fis = FileInputStream(jsonFile)
val absolutePath = imageFiles.absolutePath
lottieAnimationView.setImageAssetDelegate() {
val opts = BitmapFactory.Options()
opts.inScaled = true
var bitmap: Bitmap? = null
bitmap = BitmapFactory.decodeFile(absolutePath + File.separator + it.fileName, opts)
bitmap
}
LottieComposition.Factory.fromInputStream(fis) {
lottieAnimationView.postDelayed(Runnable {
lottieAnimationView.visibility = View.VISIBLE
},200)
it?.let { it1 -> lottieAnimationView.setComposition(it1) }
lottieAnimationView.playAnimation()
}
return fis
} catch (e: Exception) {
}
return null
}
//这个是解压缩的方法,解压缩的工具类可以从网上找一个
fun unZip(imagePath: String,destPath:String) {
val file = File(imagePath)
val destFile = File(destPath)
if (!destFile.exists()) {
destFile.mkdir()
}
if (!file.exists()) return
ZipUtils.unzipFile(file,destFile)
}
//辅助类,不重要
fun inputStreamClose(fis:FileInputStream?) {
if (fis != null) {
try {
fis.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
//辅助类,不重要
fun getGiftFileName(giftId:Int):String {
if (giftId > FileDownloadConstant.giftList.size){
return ""
}
return FileDownloadConstant.giftList[giftId?.minus(1)]
}
}
复制代码
使用方式:
val giftFileName = LottieAnimationUtils.getGiftFileName(actionAttachment.id)
val imagePath = "${FileDownloadConstant.rootPathAnimation}/$giftFileName/images"
val jsonPath = "${FileDownloadConstant.rootPathAnimation}/$giftFileName/data.json"
fis = loadLottie(lottie_likeanim, imagePath, jsonPath,giftFileName)
复制代码
大概使用方式就是这样的,以上就是一些伪代码,但是基本原理就是这样
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END