Android实现GIF播放的几种方式(附带源码)

一、项目介绍

在当今移动互联网时代,GIF 动图凭借体积小、兼容性好、动效生动的特点,被广泛用于表情包、Banner、加载动画、用户引导等场景。Android 应用要想在 UI 层面更具吸引力,往往需要集成 GIF 播放功能。但 Android 原生并不直接支持在 ImageView 中播放 GIF,需要开发者借助多种技术手段实现。

本文将从理论到实战,系统地介绍在 Android 上实现 GIF 播放的八种主流方案:

原生 Movie 类

AnimationDrawable 帧动画

Glide 库

Fresco 库

android-gif-drawable (pl.droidsonroids.gif)

Coil 库

WebView 播放

Jetpack Compose + Coil

每种方案都包含:原理剖析、依赖配置、完整代码示例(所有文件整合在一个代码块中,用注释区分)、要点解读、性能对比与优化建议。通过本篇,你将掌握在各种业务场景中灵活选择 GIF 播放方案的能力。

二、相关知识

Android 资源解析

Movie.decodeStream(InputStream):Android 原生支持 GIF 解码,但仅适用于 API 1+。

AnimationDrawable:Frame-by-frame 帧动画,通过将多张静态帧打包到 animation-list。

第三方图像加载库

Glide:基于 Bitmap 解码,支持 GIF、WebP 动图,默认将 GIF 解为 GifDrawable。

Fresco:Facebook 开源,使用 DraweeView,对 GIF 与 WebP 有专门支持。

android-gif-drawable:纯 GIF 解码库,性能优异,支持精准控制。

Coil:Kotlin-first,基于 ImageDecoder/GifDecoder,与 Compose 友好。

渲染容器

ImageView:最常用。

SimpleDraweeView:Fresco 专用。

GifImageView:android-gif-drawable 自带。

WebView:可直接加载 HTML 标签的 GIF,成本较高。

Compose:使用 AndroidView 包裹传统 View,或使用 Coil Compose 扩展。

性能考量

内存占用:解码 GIF 会产生多帧位图,需注意回收与缓存。

CPU 与耗电:高帧率动画容易导致主线程卡顿或电量快速消耗。

加载速度:本地 Asset、资源包 vs 网络 URL;可考虑异步预加载。

三、实现思路

方案一:原生 Movie

手动解码 GIF 帧,控制绘制频率。

方案二:AnimationDrawable 帧动画

在 res/drawable/ 中声明 XML,逐帧切换。

方案三:Glide

添加依赖 implementation 'com.github.bumptech.glide:glide:4.x.x',使用 Glide.with().asGif()。

方案四:Fresco

初始化 Fresco,使用 SimpleDraweeView 并 setController 加载。

方案五:android-gif-drawable

添加依赖 implementation 'pl.droidsonroids.gif:android-gif-drawable:1.x.x',使用 GifImageView。

方案六:Coil

添加依赖 implementation 'io.coil-kt:coil:2.x.x',使用 ImageView.load() 自动识别 GIF。

方案七:WebView

在 HTML 中引用 GIF,无需额外解码,兼容性最强,但内存与交互成本高。

方案八:Compose + Coil

在 Compose 中使用 AsyncImage 或 SubcomposeAsyncImage,与 Coil Compose 集成。

四、环境与依赖

// app/build.gradle

plugins {

id 'com.android.application'

id 'kotlin-android'

}

android {

compileSdkVersion 34

defaultConfig {

applicationId "com.example.gifdemo"

minSdkVersion 21

targetSdkVersion 34

}

buildFeatures { viewBinding true }

kotlinOptions { jvmTarget = "1.8" }

}

dependencies {

// Glide

implementation 'com.github.bumptech.glide:glide:4.15.1'

kapt 'com.github.bumptech.glide:compiler:4.15.1'

// Fresco

implementation 'com.facebook.fresco:fresco:2.6.0'

implementation 'com.facebook.fresco:animated-gif:2.6.0'

// android-gif-drawable

implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.27'

// Coil

implementation 'io.coil-kt:coil:2.2.2'

implementation 'io.coil-kt:coil-compose:2.2.2'

// Kotlin Coroutines for Demo

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

}

五、整合代码

// =======================================================

// 文件: AndroidManifest.xml

// 描述: 声明应用与 Fresco 初始化

// =======================================================

package="com.example.gifdemo">

android:name=".App"

android:allowBackup="true"

android:theme="@style/Theme.App">

android:exported="true">

// =======================================================

// 文件: App.kt

// 描述: Fresco 初始化

// =======================================================

package com.example.gifdemo

import android.app.Application

import com.facebook.drawee.backends.pipeline.Fresco

class App: Application() {

override fun onCreate() {

super.onCreate()

Fresco.initialize(this)

}

}

// =======================================================

// 文件: res/layout/activity_main.xml

// 描述: 首页,跳转到不同方案示例

// =======================================================

android:orientation="vertical" android:padding="16dp"

android:layout_width="match_parent" android:layout_height="match_parent">