Glide v4详解
- 简介
- 下载
- 配置
- 使用
- 简单使用
- 高级用法
- RequestOptions
- TransitionOptions
- Generated API
- RequestBuilder
- Configuration
- 使用技巧
- Glide的图片变换Transformations
- Glide的过渡动画Transitions
- Glide的缓存管理Caching
简介
Glide项目于2012年12月21日由Google工程师Sam sjudd首次提交,到现在已经迭代了四个大的版本,受到了越来越多开发者的欢迎,Star数也已接近两万。Glide v4.x相对于之前比较稳定的Glide v3.7.0来说,有了很大的变化,一个比较大的改动就是Glide处理加载选项(如裁剪变换、占位符、缓存策略等)的方式。在之前的Glide v3中,加载选项由一系列复杂的builder处理,而Glide v4中这些已经被单一类型的builder所取代,且提供了一系列可供builder使用的选项对象(options objects)。
下载
在build.gradle中添加依赖:
compile 'com.github.bumptech.glide:glide:4.3.0'annotationProcessor 'com.github.bumptech.glide:compiler:4.3.0'
Glide需要support库的支持,如果你的项目还没有依赖support库,还需要添加support-v4依赖:
compile 'com.android.support:support-v4:26.1.0'
配置
如果你使用了proguard混淆,可能需要添加如下混淆规则:
-keep public class * implements com.bumptech.glide.module.GlideModule-keep public class * extends com.bumptech.glide.AppGlideModule-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {**[] $VALUES;public *;}
你还需要声明联网、磁盘读写权限:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
使用
简单使用
很多情况下,使用Glide加载图片只需要一行代码
Glide.with(fragment).load(myUrl).into(imageView);
取消加载也一样简单:
Glide.with(fragment).clear(imageView);
虽然清理资源加载是个很好的做法,不过很多情况下你没有必要这样做,因为Glide会根据你在with()
方法中传入的Activity
/Fragment
的生命周期决定资源的加载和清理。
高级用法
RequestOptions
Glide中很多选项设置都可以通过RequestOptions
类和apply()
方法完成,包括:
- 占位符(Placeholders)
- 图片变换(Transformations)
- 缓存策略(Caching Strategies)
- 编码质量、解码配置等组件选项(Component specific options)
RequestOptions requestOptions = new RequestOptions().placeholder(R.drawable.default_avatar).circleCrop().diskCacheStrategy(DiskCacheStrategy.ALL).encodeQuality(90);Glide.with(this).load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png").apply(requestOptions).into(imageView);
placeholder
- 请求过程中显示,请求完成后被替换为请求到的资源。如果请求的资源是内存中的,placeholder可能就不会被显示。
如果请求失败且error Drawable没有设置,placeholder将继续被显示。
如果请求的url/model为空且error Drawable和fallback Drawable都没设置,placeholder将继续被显示。- error
- 当请求永远失败时显示error Drawable。
当请求的url/model为空且fallback Drawable没设置时显示error Drawable- fallback
- 当请求的url/model为空时显示fallback Drawable。
fallback Drawable主要目的是允许用户表明"空"是否被允许,因为Glide默认把空的url/model当做error处理。一个典型的场景就是未设置头像用户的avatar字段可能是null
,而显示的时候我们需要显示一个默认的用户头像,此时设置fallback是个很好地选择。- thumbnail请求
- 缩略图请求像普通的全尺寸请求一样是一个完整的资源请求,如果缩略图请求在完整请求完成之前完成,就加载并展示缩略图请求请求到的资源。
缩略图由于比全尺寸图更小所以加载的更快,不过无法保证两个请求完成的顺序。
但是,如果缩略图请求在全尺寸请求之后完成,缩略图资源并不会替换全尺寸资源。- error请求
- 从Glide v4.3.0开始,当你的主请求失败时,你可以通过
error()
API指定一个RequestBuilder
去开始一个新的请求。也就是说你可以指定一个备用请求,如果主请求成功完成那么你的errorRequestBuilder
将不会开始执行。如果你同时指定了thumbnail()
请求和error()
请求,一旦主请求失败error()
请求就开始执行,即使thumbnail()
请求成功了。
TransitionOptions
Glide可以通过TransitionOptions
设置请求完成后的显示行为,如:
- 淡入效果(View fade in)
- 交叉渐入渐出(Cross fade from the placeholder)
- 无过渡效果(No transition)
RequestOptions requestOptions = new RequestOptions().placeholder(R.drawable.default_avatar).circleCrop();DrawableTransitionOptions transitionOptions = new DrawableTransitionOptions().crossFade();Glide.with(this).load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png").apply(requestOptions).transition(transitionOptions).into(imageView);
如果不设置过渡效果,当图片加载完之后就会立刻替换之前的图片。为了避免这样突然的改变,让图片更平滑地展示,我们可以通过
TransitionOptions
添加过渡效果。不过Transitions只面对单个请求的上下文,所以你不能通过Transitions定义一个请求到另一个请求的过渡动画。
Glide v4默认不应用任何的过渡动画,如果需要必须手动为每个请求应用过渡动画。
Glide要加载的图片资源可能来自:
- Glide的内存缓存(memory cache)
- Glide的磁盘缓存(disk cache)
- 本地的File或Uri源
- 远程的Url或Uri源
如果加载的图片资源来自Glide的内存缓存,加载过程特别快,Glide的内置transitions将不会应用,其它情况Glide的内置transitions才会应用。
与RequestOptions
不同,TransitionOptions
与Glide要加载的资源类型直接关联(TranscodeType),也就是说,如果你请求一个Bitmap
,你需要使用BitmapTransitionOptions
而不是DrawableTransitionOptions
。
Generated API
可能你已经注意到了,像RequestOptions
、TransitionOptions
这些options虽然将选项设置清晰地隔离开来,但额外地去创建这些对象会影响流式编程的风格,我们更希望能够连贯地调用方法,类似这样:
GlideApp.with(fragment).load(myUrl).placeholder(placeholder).circleCrop().diskCacheStrategy(DiskCacheStrategy.ALL).transition(withCrossFade()).into(imageView);
所以,Glide v4使用annotation processor自动生成一个API,以便应用可以流式地使用包括RequestBuilder
, RequestOptions
在内的所有options。
Generated API有两个目的:
- 一些集成库可以继承Glide的API去自定义一些options
- 应用也可以继承Glide的API去添加一些绑定通用options的方法
要使用Generated API也很简单,只需要在应用中写一个AppGlideModule
的实现即可:
package com.example.myapp;import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}
编译一下(Rebuild Project),apt就会在相同包名下生成包含GlideApp在内的一系列文件 ,使用GlideApp你就可以流式地使用所有options的方法了。
RequestBuilder
每次调用Glide.with()
你都会得到一个RequestBuilder
, 而RequestBuilder
就是Glide请求的主干,负责把你的options和请求的url/model结合起来并开始新的加载。
RequestBuilder
可以指定:
- 你想要加载的资源类型(Bitmap, Drawable等)
- 你想要加载的资源的url/model
- 你想要加载资源的view
- 你想要应用的
RequestOption
对象 - 你想要应用的
TransitionOption
对象 - 你想要加载的
thumbnail()
缩略图
RequestBuilder
与你想要加载的资源类型直接关联(TranscodeType),默认返回RequestBuilder<Drawable>
,你可以通过as...
方法改变: RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();
。RequestBuilder
可以被重用去开始多个加载:
RequestBuilder<Drawable> requestBuilder =Glide.with(fragment).asDrawable().apply(requestOptions);for (int i = 0; i < numViews; i++) {ImageView view = viewGroup.getChildAt(i);String url = urls.get(i);requestBuilder.load(url).into(view);
}
Configuration
Glide v4中有两个类可以配置Glide: AppGlideModule
和LibraryGlideModule
,这两个类都可以注册ModelLoader
, ResourceDecoder
等额外组件,但只有AppGlideModule
允许更改包括缓存位置、大小在内的应用特定设置。
一个应用只能有一个AppGlideModule
实现(如果有多个编译时就会报错),所以libraries是不能提供AppGlideModule
的实现的。
为了让Glide更好地寻找AppGlideModule
和LibraryGlideModule
实现,它们的实现类必须用@GlideModule
注解,有了这个注解,Glide的annotation processor就可以在编译时找到所有的实现类了。
如果libraries想配置Glide,必须:
- 添加一到多个
LibraryGlideModule
实现 - 每个
LibraryGlideModule
都添加@GlideModule
注解 - 添加Glide的annotation processor依赖
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());}
}
compile 'com.github.bumptech.glide:annotations:4.2.0'
如果应用想配置Glide,必须有且只有一个AppGlideModule
实现,且混淆时不能混淆这些实现。
Glide默认内存缓存使用LruResourceCache
(MemoryCache
接口的实现),内存缓存的大小由MemorySizeCalculator
决定,而MemorySizeCalculator
会根据设备的RAM大小和屏幕分辨率决定内存缓存的大小。 你可以自定义缓存实现或缓存大小,如
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mbbuilder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));}
}
Glide默认磁盘缓存使用DiskLruCacheWrapper
,磁盘缓存默认大小是250 MB,默认路径是/data/data/your.application.package/cache/image_manager_disk_cache
,这个路径是应用内部缓存路径,如果你想要缓存到外部公共目录下,可以这样设置:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {builder.setDiskCache(new ExternalDiskCacheFactory(context));}
}
也可以指定内部/外部磁盘缓存大小、缓存路径:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MBbuilder.setDiskCache(new InternalDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));}
}
甚至可以自定义磁盘缓存的实现:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {builder.setDiskCache(new DiskCache.Factory() {@Overridepublic DiskCache build() {return new YourAppCustomDiskCache();}});}
}
利用AppGlideModule
,你可以为所有请求应用默认的RequestOptions
:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.RGB_565).disallowHardwareBitmaps());}
}
你也可以使用RequestManager
的applyDefaultRequestOptions
方法为某个Activity
/Fragment
应用默认的RequestOptions
:
Glide.with(fragment).applyDefaultRequestOptions(new RequestOptions().format(DecodeFormat.RGB_565).disallowHardwareBitmaps());
虽然RequestManager
也有setDefaultRequestOptions
方法来完全替换之前默认RequestOptions
(通过AppGlideModule
或RequestManager
设置的),但是为了不影响一些默认选项,使用applyDefaultRequestOptions
更安全。
当加载bitmap出错(如OOM)时,Glide默认只会打印log,你可以使用GlideExecutor.UncaughtThrowableStrategy
指定出错时的策略:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {final UncaughtThrowableStrategy myUncaughtThrowableStrategy = new ...builder.setDiskCacheExecutor(newDiskCacheExecutor(myUncaughtThrowableStrategy));builder.setResizeExecutor(newSourceExecutor(myUncaughtThrowableStrategy));}
}
为了方便调试,你可以修改Glide的Log level:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {builder.setLogLevel(Log.DEBUG);}
}
应用和Libraries都可以注册一些Glide components,包括:
ModelLoader
,用于加载自定义的Model (Urls, Uris, POJOs)和Data (InputStreams, FileDescriptors).ResourceDecoder
,用于解码Resources (Drawables, Bitmaps)或Data (InputStreams, FileDescriptors).Encoder
,用于把Data (InputStreams, FileDescriptors)写入Glide磁盘缓存.ResourceTranscoder
,用于把Resources (BitmapResource)转成其他类型的Resources (DrawableResource).ResourceEncoder
,用于把Resources (BitmapResource, DrawableResource)写入Glide磁盘缓存.
注册components的过程也很简单,只需要在AppGlideModule
或LibraryGlideModule
的registerComponents()
方法中使用Registry
注册即可:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {registry.append(Photo.class, InputStream.class, new CustomModelLoader.Factory());}
}
资源的加载过程:
一系列已注册的components(包括Glide默认已注册的和Modules中注册的)定义了一系列的加载路径(load paths),每个加载路径都是从load()
方法提供的Model到as()
方法指定的Resource类型的一步步处理,一个加载路径包含以下几个步骤:
1. Model -> Data (ModelLoader
负责)
2. Data -> Resource (ResourceDecoder
负责)
3. Resource -> Transcoded Resource (可选,ResourceTranscoder
负责).
Encoder
可以在第2步之前把Data (InputStreams, FileDescriptors)写入Glide磁盘缓存,ResourceEncoder
可以在第3步之前把Resources (BitmapResource, DrawableResource)写入Glide磁盘缓存。
当一个请求开始后,Glide将尝试所有从Model到请求的Resource类型的可用路径。如果任何一个加载路径成功,这个请求就将成功。只有所有可用加载路径都失败时,这个请求才会失败。
关于Components的顺序:
在加载的过程中,Glide将尝试每个已注册的ModelLoader
、ResourceDecoder
。而尝试的顺序,你可以通过Registry
的prepend()
, append()
, 和replace()
方法设置。
1.prepend()
将确保你的ModelLoader
和ResourceDecoder
先于所有之前注册的components调用,所以当需要处理已存在的Model/Data子集时,你需要使用prepend()
方法。如果你的ModelLoader
或ResourceDecoder
的handles()
方法返回false
或者失败时, 所有其它的ModelLoader
或ResourceDecoder
将按其注册顺序被逐个调用。如当你需要自己处理某一类String类型url的加载时,你应该使用prepend()
方法以便你自定义的ModelLoader
(继承BaseGlideUrlLoader<String>
)先于Glide默认String类型url的ModelLoader
被调用:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {registry.prepend(String.class, InputStream.class, new CustomUrlModelLoader.Factory());}
}
如果你这个自定义的ModelLoader
load失败了,会交给Glide默认行为继续处理的。
2. append()
将确保你的ModelLoader
和ResourceDecoder
只有在Glide默认选项都尝试后再调用,所以当你需要处理一个新的Model类型时,你需要使用append()
。如当你需要通过你自定义的Model对象(Photo.class)获取InputStream时:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {registry.append(Photo.class, InputStream.class, new CustomModelLoader.Factory());}
}
3.replace()
将确保Glide所有给定Model和Data的ModelLoader
都被替换成你的ModelLoader
,所以当你不想要Glide默认行为执行,只执行你自己的加载逻辑的时候,你需要使用replace()
。如当你只想使用OkHttp
网络库去请求网络资源时:
@GlideModule
public class YourAppGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());}
}
关于配置的冲突:
你的应用可能依赖多个libraries,这些libraries可能包含多个LibraryGlideModule
,有些情况下这些LibraryGlideModule
的options存在冲突或者有些options是你的应用不需要或者避免的,此时你可以给你应用的AppGlideModule
添加@Excludes
注解去解决冲突,如:
@Excludes({com.example.unwanted.GlideModule.class, com.example.conflicing.GlideModule.class})
@GlideModule
public final class MyAppGlideModule extends AppGlideModule { }
@Excludes
注解既可以用于排除LibraryGlideModule
,也可用于排除你之前使用v3版本时定义的GlideModule
。
关于之前使用v3版本时在AndroidManifest.xml中定义的 GlideModule
:
Glide v4为了向后兼容,更平滑的从v3过渡到v4,依然会解析应用和其libraries的AndroidManifest.xml文件并注册其中的GlideModule
。
如果你的应用和其libraries都已经是Glide v4的AppGlideModule
和LibraryGlideModule
,你完全可以禁用manifest解析以提高Glide初始化速度并避免潜在的解析问题:
@GlideModule
public final class MyAppGlideModule extends AppGlideModule {@Overridepublic boolean isManifestParsingEnabled() {return false;}
}
使用技巧
Glide的图片变换(Transformations)
当你使用Glide为ImageView加载图片时,Glide会根据ImageView的ScaleType自动应用相应的变换,如果scale type是CENTER_CROP
,Glide将自动应用CenterCrop
transformation,如果scale type是FIT_CENTER
或CENTER_INSIDE
,Glide将自动应用FitCenter
transformation。
很多情况下,我们需要对要显示的Resources (如Drawables, Bitmaps)进行裁剪、滤镜、模糊等处理,所以Glide内置了几种常用的transformations:
- CenterCrop
- FitCenter
- CenterInside
- CircleCrop
- RoundedCorners
应用这些transformations也很简单:
RequestOptions requestOptions = new RequestOptions().fitCenter();
Glide.with(fragment).load(url).apply(requestOptions).into(imageView);
import static com.bumptech.glide.request.RequestOptions.fitCenterTransform;
Glide.with(fragment).load(url).apply(fitCenterTransform()).into(imageView);
GlideApp.with(fragment).load(url).fitCenter().into(imageView);
GlideApp.with(fragment).load(url).transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation()).into(imageView);
GlideApp.with(fragment).load(url).transforms(new FitCenter(), new YourCustomTransformation()).into(imageView);
其实本质都是调用RequestOptions
的transform()
方法,对于多个变换来说,MultiTransformation
构造器的参数顺序决定了变换的应用顺序。
如果需要更多的图片变换可以参考 shangmingchao/GlideTransformation 或 wasabeef/glide-transformations 的自定义Transformations。
Glide的过渡动画(Transitions)
前面已经提到了,Glide的Transitions可以让图片更平滑地展示,但是在Android中使用动画是非常昂贵的,尤其是一次开启很多动画。而Cross fade及其他过渡动画对于透明度的动态改变也是特别昂贵的,更糟糕的情况下动画的执行时间甚至比解码所花费的时间还要长,所以无理由地在列表中使用动画可能会造成卡顿。为了最大化性能,最好避免在ListView
、GridView
或RecyclerView
中使用Glide的加载动画,尤其是你希望图片更快的显示和缓存时。
Glide默认的cross fades动画是基于Android的TransitionDrawable的,TransitionDrawable
提供了两种动画模式,由setCrossFadeEnabled()
方法控制,当cross fades被禁用时,过渡图片会淡入到已显示的图片上面,当cross fades启用时,过渡图片会从透明逐渐变成不透明,之前的图片会从不透明变成透明。
Glide默认是禁用cross fades的,因为启用时两个图片透明度的同时变化可能会产生白色闪烁,还是禁用更好一点。但禁用cross fades也会产生一些问题:当placeholder比要加载的图片大或者要加载的图片是透明的时,禁用cross fades将会导致placeholder显示在要显示的图片下面。 你可以使用new DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true))
启用cross fades。
Android TransitionDrawable
的cross fades动画还有个Bug,如果两张图片的宽高比不一样,会导致图片变形,所以慎用cross fades动画。
Glide的缓存管理(Caching)
Glide在开始一个新的图片请求之前,会检查一下各级缓存:
- Active resources - 要加载的图片是否正显示在其他View上?
- Memory cache - 要加载的图片是否最近加载过且还在内存中?
- Resource - 要加载的图片是否已经被解码、变换且写入过磁盘缓存?
- Data - 要加载的图片的原始data是否可以从磁盘缓存中获取到?
前两步是检查图片资源是否在内存中,如果在则马上返回图片资源。后两步是检查图片资源是否在磁盘缓存中,如果是则尽快异步返回图片资源。
如果这4步都没能获取到图片,Glide才会根据model(如File, Uri, Url)去获取原始资源。
Glide中缓存的cache keys包含很多元素,至少包括model(如File, Uri, Url)和可选的Signature
。事实上,第1-3步(Active resources, memory cache, resource disk cache)的cache keys还是包括图片的宽高、可选的Transformation
、已添加的Options
以及请求的数据类型 (如Bitmap, GIF)等元素,为了生成磁盘缓存上的cache keys名称,cache keys的每个元素都会被哈希化以创建一个String key,并在随后作为磁盘缓存上的文件名使用。
可以使用RequestOptions
的diskCacheStrategy()
方法为某个请求指定磁盘缓存策略,默认的缓存策略是AUTOMATIC
:
AUTOMATIC
- 请求远程数据时只缓存未经更改的原始data,请求本地数据时将缓存变换后的resourceDATA
- 缓存未经decoded的原始dataRESOURCE
缓存decoded后的resourceALL
- 请求远程数据时缓存DATA
和RESOURCE
,请求本地数据时只缓存RESOURCE
NONE
不缓存
GlideApp.with(fragment).load(url).diskCacheStrategy(DiskCacheStrategy.ALL).into(imageView);
有些情况下(如无图模式/省流模式),我们希望Glide只从缓存中获取图片资源,可以借助RequestOptions
的onlyRetrieveFromCache()
方法:
GlideApp.with(fragment).load(url).onlyRetrieveFromCache(true).into(imageView);
跳过内存缓存:
GlideApp.with(fragment).load(url).skipMemoryCache(true).into(view);
跳过磁盘缓存:
GlideApp.with(fragment).load(url).diskCacheStrategy(DiskCacheStrategy.NONE).into(view);
清除内存缓存:
// 必须在主线程中调用
Glide.get(context).clearMemory();
清除磁盘缓存:
// 必须在工作线程中调用
Glide.get(applicationContext).clearDiskCache();
刷新缓存: 你可以通过RequestOptions
的signature()
方法向内存缓存和磁盘缓存的cache keys中添加额外的数据元素,以更自由地控制缓存失效与刷新。如你想要版本号也作为cache keys的一部分,当版本号更改时刷新这些缓存:
GlideApp.with(yourFragment).load(yourFileDataModel).signature(new ObjectKey(yourVersionMetadata)).into(yourImageView);
Glide v4详解相关推荐
- Glide使用详解(一)
该文章基于Glide v3.7.0版本 Glide v4版本详解请移步: http://blog.csdn.net/shangmingchao/article/details/78219558 一. ...
- Android平滑图片加载和缓存库 Glide 使用详解
版权声明:本文原创作者:一叶飘舟 作者博客地址:http://blog.csdn.net/jdsjlzx 一.简介 在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide的图片加载库,作者 ...
- Android开发中显示图片Glide使用详解(Google推荐)
一.简介 Glide,一个被google所推荐的图片加载库,作者是bumptech.这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方app.(PS:众所 ...
- Android平滑图片加载和缓存库Glide使用详解
在图片加载库烂大街的今天,选择一个适合自己使用的图片加载库已经成为了每一个Android开发者的必经之路.现在市面上知名的图片加载库有UIL,Picasso,Volley ImageLoader,Fr ...
- 图片加载框架Glide使用详解
最终我还是决定使用Glide,作为我以后的主要图片加载框架.主要基于三点考虑 代码有人维护,不至于出现问题,项目组都搞不定的时候问题无法解决.(ImageLoader已没人维护了) 代码简洁,可读性很 ...
- [玩转UE4/UE5动画系统>应用篇>功能模块] 之 ALS V4地面站立动作状态机详解
本教程采用图文教程+视频教程的多元化形式,我会为不同的知识点选择适当的表达方式.教程内容将同步免费发布于 开发游戏的老王(知乎|CSDN)的专栏<玩转UE4/UE5动画系统>.教程中使用的 ...
- android V1,V2,V3,V4签名详解
前言 最近帮测试做了一点关于签名的需求,今天就和各位同学简单聊一聊关于签名的那些事儿. 如果问到 Android 为什么需要签名?大家都可能想到官网的解释: ❝ Android 系统要求所有 APK ...
- thinksnsv4.6运行php,SNS社交系统“ThinkSNS V4.6”活动应用功能详解及应用场景举例...
ThinkSNS是什么? ThinkSNS(简称TS)是一款起始于2008年的全平台综合性的sns社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS ...
- [玩转UE4/UE5动画系统>应用篇>功能模块] 之 ALS V4 主状态机详解
本教程采用图文教程+视频教程的多元化形式,我会为不同的知识点选择适当的表达方式.教程内容将同步免费发布于 开发游戏的老王(知乎|CSDN)的专栏<玩转UE4/UE5动画系统>.教程中使用的 ...
最新文章
- Socket IO与NIO(二)
- 电子电路基础复习 —— 三极管
- 第三届传智杯全国大学生IT技能大赛(决赛B组)【c++】
- UVA - 1415 Gauss Prime(高斯素数)
- 谈下关于kaggle的反作弊规则
- 【Leetcode | 】93. 复原IP地址
- 对不起,我把APP也给爬了
- 怎么在QQ浏览器上使用微信聊天?
- 中文情感分析——snownlp类库 源码注释及使用
- 译:在C#中使用LINQ To SQL
- 三个步骤教你-----如何实现DHCP中继配置
- 激情彭拜的10月英语学习
- 华为数字化转型之道第四讲
- ​【技术】机器视觉技术原理解析及应用领域
- JavaWeb HTML
- Nand2Tetris - Week 1
- 2018省赛第九届蓝桥杯真题C语言B组第九题题解 全球变暖
- MYSQL数据库设计和数据库设计实例(二)
- SAML 协议-简单的SAML
- 从三室心脏MRI影像检测主动脉瓣病变
热门文章
- 超详细的 Wireshark 使用教程
- 在vue中禁止input框和textarea编辑的操作
- 三国志战略版:三势贾的另类搭配,也可以这么强?
- 【PyTorch】模型 FPS 测试 Benchmark(参考 MMDetection 实现)
- linux命令 查看分辨率,linux怎样在命令行模式修改屏幕分辨率
- 按键精灵9.5.1.11790秒速启动,多余元素全灭版
- android studio zbar,Zbar and Zxing in android studio
- 测试开发 | 接口测试之HTTP 协议讲解
- execjs安装及相关问题解决
- ListT的各种排序方法