Glide简单使用
- Gradle集成
implementation 'com.github.bumptech.glide:glide:3.7.0'
- 加载图片
Glide.with(this).load(url).into(imageView);
具体使用请参考最新版本Glide中文文档 关于 Glide
加载流程源码解析
- 上下文Context,RequestManagerRetriever#get
public RequestManager get(FragmentActivity activity) {
//根据Looper.myLooper() == Looper.getMainLooper();判断是否是UI线程
if (Util.isOnBackgroundThread()) {
//如果非UI线程,则用Application的Context
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);//如果activity销毁了,则抛异常
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}
Context为null时一般是activity因异常销毁了,此时不加载图片即可,无需抛异常让程序崩溃。
- Glide生命周期与activity绑定,RequestManagerRetriever#supportFragmentGet
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
//SupportRequestManagerFragment继承Fragment,为绑定与activity的生命周期
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(
context, current.getLifecycle(),
current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
- 观察者模式 批量处理生命周期回调
RequestManager调用addListener添加实例到ActivityFragmentLifecycle内部集合中。
RequestManager(Context context, final Lifecycle lifecycle,
RequestManagerTreeNode treeNode, RequestTracker requestTracker,
ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
if (Util.isOnBackgroundThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
lifecycle.addListener(RequestManager.this);
}
});
} else {
//将自身实例添加到ActivityFragmentLifecycle中受其批量响应回调
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
}
SupportRequestManagerFragment里ActivityFragmentLifecycle根据fragment生命周期响应回调
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
RequestManager内被回调onStart,onStop,onDestroy
@Override
public void onStart() {
//开始/恢复网络请求
resumeRequests();
}
@Override
public void onStop() {
//暂停网络请求
pauseRequests();
}
@Override
public void onDestroy() {
//断开网络请求,释放资源
requestTracker.clearRequests();
}
- 发起图片请求,GenericRequestBuilder#into
public <Y extends Target<TranscodeType>> Y into(Y target) {
//target 对象是用来最终展示图片的,并在加载过程中处理生命周期事件。
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//构建Request,GenericRequest实体类
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
//发起请求
requestTracker.runRequest(request);
return target;
}
- 图片属性配置,GenericRequest#begin
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
//判断是否自定义宽高
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//设置宽高,内部开启线程,设置缓存
onSizeReady(overrideWidth, overrideHeight);
} else {
//根据imageview的宽高,计算出图片显示的宽高(采样率压缩原理)
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
上面涉及到的采样率压缩可以参考 Bitmap知识点。
- 开启线程,Engine#load
public <T, Z, R> LoadStatus load(Key signature, int width, int height,
DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider,
Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable,
DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
...
//开启线程,异步加载图片
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
//图片解码
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
- 下载任务,HttpUrlFetcher#loadDataWithRedirects
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
throws IOException {
...
//常规的网络请求配置
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
//建立连接
urlConnection.connect();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
- InputStream转码成Bitmap,Downsampler#decodeStream
private static Bitmap decodeStream(MarkEnforcingInputStream is,
RecyclableBufferedInputStream bufferedStream,BitmapFactory.Options options) {
if (options.inJustDecodeBounds) {
is.mark(MARK_POSITION);
} else {
bufferedStream.fixMarkLimit();
}
final Bitmap result = BitmapFactory.decodeStream(is, null, options);
try {
if (options.inJustDecodeBounds) {
is.reset();
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.ERROR)) {
Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds
+ " sample=" + options.inSampleSize, e);
}
}
return result;
}
- 缓存机制
Glide的缓存模式分为内存缓存、硬盘缓存。缓存机制一般采用LruCache算法,即近期最少使用算法。
可参考Android-Universal-Image-Loader源码知识笔记