Gif文件是由多张静态图片组合而成,每张图片都有自己的显示时间,屏幕通过连续显示这些图片,以达到动态图的目的,由于这些特性,导致如果用java去解码,可能效率不是那么高,因为java能运行速度始终无法匹敌c/c++,所以用jni技术,通过c/c++代码解码gif文件,再将解析得到的单张图片以及对应的显示时间返回到java层,再呈现到view上是比较好的方式。
我通过学习github上一些开源代码,制作了一个这样的c++代码库(使用方式类似Glide只需要一行代码),可以实现gif的解码,还可以制作gif动态图,基于Android Studio项目架构,使用cmake方式编译,地址:
https://github.com/yylyingy/SimpleGif
SimpleGif与Glide性能对比图:
Glide cpu and memory usage:
SimpleGif cpu and memory usage:
上面两张图显示了SimpleGif与Glide同时加载9张Gif时CPU占用率以及内存占用,可以看到SimpleGif在这两项性能上均占优,看到SimpleGif的性能如此优异,是不是迫不及待的想要使用了,接下来将介绍SimpleGif的用法以及Sample实例;
首先将上面链接的项目clone到本地,在项目中,module library属于android library,如果想要在你自己的项目中使用,可以通过Android Studio的Import module导入到你自己的项目中(需要配置ndk路径,以及安装了cmake);
library这个module采用的是cmake方式编译,通过配置library/CMakeLists.txt来指定需要编译的c/c++源文件,编译后的动态链接库name,以及需要用到的libraries等等,c/c++源文件列表:
CMakeLists.txt内容:
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
#add_compile_options(-std=c++03)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
include_directories(D:/Android/WorkSpaseForAS/TestLibjpeg/app/libs)
add_library( # Sets the name of the library.
androidndkgif
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
#src/main/cpp/native-lib.cpp
src/main/cpp/DataBlock.cpp
src/main/cpp/BitWritingBlock.cpp
src/main/cpp/GifDecoder.cpp
src/main/cpp/GifEncoder.cpp
src/main/cpp/GifFrame.cpp
src/main/cpp/io_github_yylyingy_gifencodedecode_GifDecoder.cpp
src/main/cpp/io_github_yylyingy_gifencodedecode_GifEncoder.cpp
src/main/cpp/GCTGifEncoder.cpp
src/main/cpp/LCTGifEncoder.cpp
src/main/cpp/SimpleGCTEncoder.cpp
src/main/cpp/BaseGifEncoder.cpp
)
#include_directories(src/main/cpp/include)
#add_library( libjpeg SHARED IMPORTED )
#这句话是jpeg对应的so文件,so文件是放到ibs这个文件夹中(相对与cpp这个文件的位置)
#set_target_properties(libjpeg PROPERTIES IMPORTED_LOCATION
#D:/Android/WorkSpaseForAS/TestLibjpeg/libjpeg/libs/${ANDROID_ABI}/libjpeg.so)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
androidndkgif
# Links the target library to the log library
# included in the NDK.
${log-lib}
#jnigraphics这个是android下面的bitmap.h对应的库
jnigraphics)
module library的build.gradle内容:
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""//""-std=c++11"
}
}
ndk{
abiFilters 'x86','armeabi-v7a','armeabi'
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.2.0'
testCompile 'junit:junit:4.12'
}
做好了这些,便可以调用library里的java api实现gif解码了,
java 文件:
这里我封装成了SimpleGif库,可以像Glide那样一行代码即可
java代码调用范例:
SimpleGif.with(this).load(setupSampleFile()).into(imageView);
只需要一行代码,即可实现gif绘制到ImageView,api与Glide十分相似,并且解码使用了jni,效率应该大大提升效果图: