前言
近期研究了一下Glide的圖片加載框架,在這里和大家分享一下。由于代碼研讀有限,難免有錯誤的地方,了解的童鞋還望指正。
本篇是Glide框架及源碼解析的第二篇,更多文章敬請關注后續文章。如果這篇文章對大家學習Glide有幫助,還望大家多多轉載。
版權歸作者所有,如有轉發,請注明文章出處:http://www.lxweimin.com/u/d43d948bef39
相關文章:
跟著源碼學設計:Glide框架及源碼解析(一)
跟著源碼學設計:Glide框架及源碼解析(二)
跟著源碼學設計:Glide框架及源碼解析(三)
跟著源碼學設計:Glide框架及源碼解析(四)
跟著源碼學設計:Glide框架及源碼解析(五)
1. Request管理機制
在上一篇中我們剖析了Glide的生命周期綁定機制,這一篇我們緊接著Glide的處理流程來學習一下Glide的請求管理機制。
我們先來看一下Glide的最簡單的使用代碼示例:
ImageView ivImage = (ImageView) findViewById(R.id.ivImage);
Glide.with(ivImage.getContext()) //獲取RequestManager對象
.load(url); //設置Request對象需要的資源鏈接
.into(ivImage); //獲取Request對象并綁定viewTarget -> 發起網絡請求
該段代碼十分簡潔,但是內部實現的功能卻十分的強大,比如:
- request的生命周期管理(如:退出或者隱藏了界面,需求就取消或暫停了)
- viewTarget的生命周期管理
- 資源的復用和釋放
- 靈活的配置(request的builder模式)
針對這些問題,后面將會一一展開剖析。
2. request及其生命周期管理
- 通過上一篇的學習,我們知道了Glide內部生命周期接口為LifecycleListener
- RequestManager具有生命周期(實現了LifecycleListener接口)
- request由RequestManager的into()方法族獲得
- request的生命周期由RequestManager統一管理
3. Glide請求管理機制類圖
RequestManager是如何生成request并管理request隊列的?
老規矩,先上圖:
Glide請求管理機制類圖
如圖:
- RequestManager持有一個RequestTracker對象requestTracker。
- requestTracker對象維護request的隊列集合
- RequestManager的load()函數用于獲取GenericRequestBuilder對象(其實是子類對象)
- load()內部調用loadGeneric()方法,將requestTracker對象引用傳遞給GenericRequestBuilder類
- load()實際調用GenericRequestBuilder.load()方法完成request的URL設置
- GenericRequestBuilder的into()方法是實際產生request和消費request的地方。
- GenericRequestBuilder的into(target)方法調用obtainReauest()獲取到GenericRequest對象request,request與target相互綁定并被requestTracker維護。
3.1 GenericRequestBuilder的into(target)方法
public <Y extends Target<TranscodeType>> Y into(Y 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())");
}
//因為target和request是相互綁定的,所以考慮到復用的情景時,可以先獲取一下request
Request previous = target.getRequest();
//previous != null說明target有復用,需要釋放之前綁定的資源
//注意:request內部是綁定了資源的,這里還沒有講到,先知道這回事,后面會講
if (previous != null) {
//釋放資源,防內存泄漏
//這段代碼是精華,需要好好體會:
//Glidek肯定支持view的復用(對吧?),那么復用的view資源是如何綁定和釋放的?
//這里就是資源釋放的地方(入口),資源在何時綁定會在后續的課程講到。
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//獲取需求對象(對象綁定了target)
Request request = buildRequest(target);
//target綁定需求
target.setRequest(request);
//因為target具有生命周期,即實現了LifecycleListener方法,所以將其注冊給ActivityFragmentLifecycle統一管理(不知道是啥的去看上一篇文章)
lifecycle.addListener(target);
//將需求加入隊列并執行需求
//注意是單線程
requestTracker.runRequest(request);
return target;
}
3.2 request的生命周期管理
- 根據上文得知,request都被加入到requestTracker中來管理
- requestTracker由RequestManager創建和管理
- RequestManager具有生命周期
3.2.1 RequestManager
下面讓我們看看RequestManager在各個生命周期回調里都做了什么
@Override
public void onStart() {
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
@Override
public void onDestroy() {
requestTracker.clearRequests();
}
public void pauseRequests() {
Util.assertMainThread();
requestTracker.pauseRequests();
}
public void resumeRequests() {
Util.assertMainThread();
requestTracker.resumeRequests();
}
//下面的兩個回調其實和request的關系沒有那么直接,先放在這里留個印象
public void onTrimMemory(int level) {
glide.trimMemory(level);
}
public void onLowMemory() {
glide.clearMemory();
}
代碼很清楚了吧。細心的同學可能注意到了onTrimMemory(int level)和onLowMemory(),這倆貨是系統在資源不足時調用的,說白了就是釋放內存,具體怎么搞得,后續文章會專門講到Glide的內存管理機制(也是精華)
3.2.2 requestTracker
最后讓我們看看requestTracker都干啥了吧
public class RequestTracker {
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List<Request> pendingRequests = new ArrayList<Request>();
private boolean isPaused;
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
// Visible for testing.
void addRequest(Request request) {
requests.add(request);
}
/**
* Stops tracking the given request.
*/
public void removeRequest(Request request) {
requests.remove(request);
pendingRequests.remove(request);
}
/**
* Returns {@code true} if requests are currently paused, and {@code false} otherwise.
*/
public boolean isPaused() {
return isPaused;
}
/**
* Stops any in progress requests.
*/
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
/**
* Starts any not yet completed or failed requests.
*/
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
/**
* Cancels all requests and clears their resources.
*/
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
request.clear();
}
pendingRequests.clear();
}
/**
* Restarts failed requests and cancels and restarts in progress requests.
*/
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled()) {
// Ensure the request will be restarted in onResume.
request.pause();
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
}
}
(本篇是Glide框架及源碼解析的第二篇,更多文章敬請關注后續文章。版權歸作者所有,如有轉發,請注明文章出處:原文鏈接)