简介篇: Glide框架
迁移篇:Glide V4 框架新特性(Migrating from v3 to v4)
基础篇:Android开发中使用Glide V4 中Generated API特性
进级篇:Kotlin编程开发之Glide V4使用OkHttp3作为传输层
前言:
在项目开发中,是需要经常用到圆形图片的,设置默认图片,设置资源图片等等。
若是,异常图片,默认图片都需要美工妹子做成圆形图片,无疑增加了美工妹子的工作量。本着当活雷锋的思想,程序员能搞定的事情,绝不麻烦美工妹子。
要说图片异步加载框架,现今最流行的非Glide莫属,连谷歌I/O App都在使用,可见它的强大之处。
众所周知,Glide的开启加载是通过调用GlideApp.with().....into()或者preload()
.
/**
* Set the target the resource will be loaded into.
*
* @param target The target to load the resource into.
* @return The given target.
* @see RequestManager#clear(Target)
*/
public > Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
void track(Target> target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
@Override
public void begin() {
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
可以从源码target.onLoadStarted(getPlaceholderDrawable())
发觉,最后是通过Target对象的onLoadStarted()方法来设置默认空白图片的。
SingleRequest类中设置异常图片的源码:
private void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
if (model == null) {
error = getFallbackDrawable();
}
// Either the model isn't null, or there was no fallback drawable set.
if (error == null) {
error = getErrorDrawable();
}
// The model isn't null, no fallback drawable was set or no error drawable was set.
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(error);
}
可以从源码target.onLoadFailed(error)
可知,是通过Target对象的onLoadFailed()方法来设置异常图片的。
长征路已经走完一半,已经找到了最后的源码走向。剩下来,只需要自定义一个Target子类。
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter {
@Nullable
private Animatable animatable;
public ImageViewTarget(ImageView view) {
super(view);
}
/**
* Returns the current {@link android.graphics.drawable.Drawable} being displayed in the view
* using {@link android.widget.ImageView#getDrawable()}.
*/
@Override
@Nullable
public Drawable getCurrentDrawable() {
return view.getDrawable();
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param drawable {@inheritDoc}
*/
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param errorDrawable {@inheritDoc}
*/
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
setDrawable(errorDrawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
@Override
public void onResourceReady(Z resource, @Nullable Transition super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
@Override
public void onStop() {
if (animatable != null) {
animatable.stop();
}
}
private void setResourceInternal(@Nullable Z resource) {
maybeUpdateAnimatable(resource);
setResource(resource);
}
private void maybeUpdateAnimatable(@Nullable Z resource) {
if (resource instanceof Animatable) {
animatable = (Animatable) resource;
animatable.start();
} else {
animatable = null;
}
}
protected abstract void setResource(@Nullable Z resource);
}
从源码可知,无论是空白图片,还是异常图片都是最后走向到setDrawable(Drawable drawable)
。
源码寻找之路已经走完,马上就可以实现自己需要的需求,继续撸起。
分析:
setDrawable(Drawable drawable)
,异常,默认空白图片设置为圆形。setResource( Bitmap resource)
,正常加载的资源图片设置为圆形代码编写如下:
/**
*
* 设置 默认图片,异常图片,指定路径的图片为圆角图片
*/
public class CircleBitmapTarget extends ImageViewTarget<Bitmap> {
public CircleBitmapTarget(ImageView view) {
super(view);
}
/**
* 从指定路径加载的Bitmap
* @param resource
*/
@Override
protected void setResource(@Nullable Bitmap resource) {
bindCircleBitmapToImageView(resource);
}
/**
*
* onLoadFailed()和onLoadStarted调用该方法,用于设置默认的图片和异常图片
* 设置默认图片
* @param drawable
*/
@Override
public void setDrawable(Drawable drawable) {
if (drawable instanceof BitmapDrawable){
Bitmap bitmap1= ((BitmapDrawable) drawable).getBitmap();
bindCircleBitmapToImageView(bitmap1);
}else{
view.setImageDrawable(drawable);
}
}
/**
* 通过RoundedBitmapDrawable绘制圆形Bitmap,且加载ImageView.
* @param bitmap
*/
private void bindCircleBitmapToImageView(Bitmap bitmap){
RoundedBitmapDrawable bitmapDrawable= RoundedBitmapDrawableFactory.create(view.getContext().getResources(),bitmap);
bitmapDrawable.setCircular(true);
view.setImageDrawable(bitmapDrawable);
}
}
最后使用方式:
GlideRequest glideRequest = GlideApp.with(context).asBitmap();
glideRequest.load(imageUrl).error(errorResourceId)//异常时候显示的图片
.placeholder(placeResourceId)//加载成功前显示的图片
.fallback(nullResourceId)//url为空的时候,显示的图片
.into(new CircleBitmapTarget(imageView));//在RequestBuilder 中使用自定义的ImageViewTarget