Lottie动画资源放到服务器预下载

最近在做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
喜欢就支持一下吧
点赞0 分享