You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android界面绘制时Lottie动画冻结问题及线程方案咨询

解决Lottie动画在界面绘制时冻结的问题

问题根源

你的代码中使用了LottieCompositionFactory.fromJsonInputStreamSync这个同步解析方法,如果在主线程执行,会直接阻塞UI线程。当收到后台响应后,界面本身需要进行重绘操作,此时主线程又被Lottie Composition的解析占用,导致Lottie动画无法及时更新帧,最终出现冻结。

核心结论

不能把LottieDrawable的播放逻辑放到工作线程(因为Drawable的绘制、动画更新都依赖UI线程),但可以将Lottie Composition的解析操作移到后台线程,这才是解决冻结的关键。

解决方案

1. 使用Lottie自带的异步API解析(Java)

将同步解析替换为异步回调,让解析过程在后台线程执行,完成后回到主线程设置Drawable:

// 定义加载回调接口
public interface OnLottieLoadedListener {
    void onLoaded(LottieDrawable drawable);
    void onFailed(Exception e);
}

// 异步加载LottieDrawable的方法
public static void getLottieFromInputStreamAsync(@NonNull InputStream inputStream, @NonNull OnLottieLoadedListener listener) {
    LottieCompositionFactory.fromJsonInputStream(inputStream, null)
        .addListener(composition -> {
            LottieDrawable drawable = new LottieDrawable();
            drawable.enableMergePathsForKitKatAndAbove(true);
            drawable.setComposition(composition);
            drawable.playAnimation();
            listener.onLoaded(drawable);
        })
        .addFailureListener(listener::onFailed);
}

// 调用示例
try {
    InputStream inputStream = pContext.getAssets().open(pImageName);
    getLottieFromInputStreamAsync(inputStream, new OnLottieLoadedListener() {
        @Override
        public void onLoaded(LottieDrawable drawable) {
            // 主线程中设置布局背景
            layout.setBackground(drawable);
        }

        @Override
        public void onFailed(Exception e) {
            // 处理加载失败逻辑,比如设置默认背景
        }
    });
} catch (IOException e) {
    e.printStackTrace();
}

2. 使用Kotlin协程优化(推荐)

如果项目使用Kotlin,协程可以更简洁地实现后台解析+主线程更新:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import androidx.lifecycle.lifecycleScope

// 后台解析LottieComposition
suspend fun loadLottieDrawable(inputStream: InputStream): LottieDrawable? {
    return withContext(Dispatchers.IO) {
        val compositionResult = LottieCompositionFactory.fromJsonInputStream(inputStream, null).await()
        compositionResult.value?.let { composition ->
            LottieDrawable().apply {
                enableMergePathsForKitKatAndAbove(true)
                setComposition(composition)
                playAnimation()
            }
        }
    }
}

// 在Activity/Fragment中调用
lifecycleScope.launch {
    try {
        val inputStream = pContext.assets.open(pImageName)
        val lottieDrawable = loadLottieDrawable(inputStream)
        lottieDrawable?.let {
            layout.background = it
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

3. 额外优化:缓存解析后的Composition

如果同一个动画会被多次使用,可以缓存解析好的Composition,避免重复解析提升性能:

private static final HashMap<String, LottieComposition> COMPOSITION_CACHE = new HashMap<>();

public static void getLottieFromInputStreamAsync(@NonNull String imageName, @NonNull InputStream inputStream, @NonNull OnLottieLoadedListener listener) {
    // 先从缓存取,避免重复解析
    if (COMPOSITION_CACHE.containsKey(imageName)) {
        LottieComposition composition = COMPOSITION_CACHE.get(imageName);
        LottieDrawable drawable = new LottieDrawable();
        drawable.enableMergePathsForKitKatAndAbove(true);
        drawable.setComposition(composition);
        drawable.playAnimation();
        listener.onLoaded(drawable);
        return;
    }

    LottieCompositionFactory.fromJsonInputStream(inputStream, null)
        .addListener(composition -> {
            COMPOSITION_CACHE.put(imageName, composition);
            LottieDrawable drawable = new LottieDrawable();
            drawable.enableMergePathsForKitKatAndAbove(true);
            drawable.setComposition(composition);
            drawable.playAnimation();
            listener.onLoaded(drawable);
        })
        .addFailureListener(listener::onFailed);
}

关键注意事项

  • LottieDrawable的playAnimation()、setComposition()必须在主线程调用,不能放到后台线程。
  • 异步解析完成后,一定要回到主线程更新UI(上述代码的回调/协程切换已经处理了这一点)。

内容的提问来源于stack exchange,提问作者Vijayadhas Chandrasekaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:56:31