前言
近期研究了一下Glide的圖片加載框架姜胖,在這里和大家分享一下钦勘。由于代碼研讀有限示血,難免有錯(cuò)誤的地方棋傍,了解的童鞋還望指正。
本篇是Glide框架及源碼解析的第二篇难审,更多文章敬請(qǐng)關(guān)注后續(xù)文章瘫拣。如果這篇文章對(duì)大家學(xué)習(xí)Glide有幫助,還望大家多多轉(zhuǎn)載告喊。
版權(quán)歸作者所有麸拄,如有轉(zhuǎn)發(fā),請(qǐng)注明文章出處:http://www.reibang.com/u/d43d948bef39
相關(guān)文章:
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(一)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(二)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(三)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(四)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(五)
1. Request管理機(jī)制
在上一篇中我們剖析了Glide的生命周期綁定機(jī)制黔姜,這一篇我們緊接著Glide的處理流程來學(xué)習(xí)一下Glide的請(qǐng)求管理機(jī)制拢切。
我們先來看一下Glide的最簡單的使用代碼示例:
ImageView ivImage = (ImageView) findViewById(R.id.ivImage);
Glide.with(ivImage.getContext()) //獲取RequestManager對(duì)象
.load(url); //設(shè)置Request對(duì)象需要的資源鏈接
.into(ivImage); //獲取Request對(duì)象并綁定viewTarget -> 發(fā)起網(wǎng)絡(luò)請(qǐng)求
該段代碼十分簡潔,但是內(nèi)部實(shí)現(xiàn)的功能卻十分的強(qiáng)大秆吵,比如:
- request的生命周期管理(如:退出或者隱藏了界面淮椰,需求就取消或暫停了)
- viewTarget的生命周期管理
- 資源的復(fù)用和釋放
- 靈活的配置(request的builder模式)
針對(duì)這些問題,后面將會(huì)一一展開剖析纳寂。
2. request及其生命周期管理
- 通過上一篇的學(xué)習(xí)主穗,我們知道了Glide內(nèi)部生命周期接口為LifecycleListener
- RequestManager具有生命周期(實(shí)現(xiàn)了LifecycleListener接口)
- request由RequestManager的into()方法族獲得
- request的生命周期由RequestManager統(tǒng)一管理
3. Glide請(qǐng)求管理機(jī)制類圖
RequestManager是如何生成request并管理request隊(duì)列的?
老規(guī)矩毙芜,先上圖:
如圖:
- RequestManager持有一個(gè)RequestTracker對(duì)象requestTracker忽媒。
- requestTracker對(duì)象維護(hù)request的隊(duì)列集合
- RequestManager的load()函數(shù)用于獲取GenericRequestBuilder對(duì)象(其實(shí)是子類對(duì)象)
- load()內(nèi)部調(diào)用loadGeneric()方法,將requestTracker對(duì)象引用傳遞給GenericRequestBuilder類
- load()實(shí)際調(diào)用GenericRequestBuilder.load()方法完成request的URL設(shè)置
- GenericRequestBuilder的into()方法是實(shí)際產(chǎn)生request和消費(fèi)request的地方腋粥。
- GenericRequestBuilder的into(target)方法調(diào)用obtainReauest()獲取到GenericRequest對(duì)象request晦雨,request與target相互綁定并被requestTracker維護(hù)。
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())");
}
//因?yàn)閠arget和request是相互綁定的隘冲,所以考慮到復(fù)用的情景時(shí)闹瞧,可以先獲取一下request
Request previous = target.getRequest();
//previous != null說明target有復(fù)用,需要釋放之前綁定的資源
//注意:request內(nèi)部是綁定了資源的对嚼,這里還沒有講到夹抗,先知道這回事,后面會(huì)講
if (previous != null) {
//釋放資源纵竖,防內(nèi)存泄漏
//這段代碼是精華漠烧,需要好好體會(huì):
//Glidek肯定支持view的復(fù)用(對(duì)吧杏愤?),那么復(fù)用的view資源是如何綁定和釋放的已脓?
//這里就是資源釋放的地方(入口)珊楼,資源在何時(shí)綁定會(huì)在后續(xù)的課程講到。
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//獲取需求對(duì)象(對(duì)象綁定了target)
Request request = buildRequest(target);
//target綁定需求
target.setRequest(request);
//因?yàn)閠arget具有生命周期度液,即實(shí)現(xiàn)了LifecycleListener方法厕宗,所以將其注冊(cè)給ActivityFragmentLifecycle統(tǒng)一管理(不知道是啥的去看上一篇文章)
lifecycle.addListener(target);
//將需求加入隊(duì)列并執(zhí)行需求
//注意是單線程
requestTracker.runRequest(request);
return target;
}
3.2 request的生命周期管理
- 根據(jù)上文得知,request都被加入到requestTracker中來管理
- requestTracker由RequestManager創(chuàng)建和管理
- RequestManager具有生命周期
3.2.1 RequestManager
下面讓我們看看RequestManager在各個(gè)生命周期回調(diào)里都做了什么
@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();
}
//下面的兩個(gè)回調(diào)其實(shí)和request的關(guān)系沒有那么直接堕担,先放在這里留個(gè)印象
public void onTrimMemory(int level) {
glide.trimMemory(level);
}
public void onLowMemory() {
glide.clearMemory();
}
代碼很清楚了吧已慢。細(xì)心的同學(xué)可能注意到了onTrimMemory(int level)和onLowMemory(),這倆貨是系統(tǒng)在資源不足時(shí)調(diào)用的霹购,說白了就是釋放內(nèi)存佑惠,具體怎么搞得,后續(xù)文章會(huì)專門講到Glide的內(nèi)存管理機(jī)制(也是精華)
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框架及源碼解析的第二篇齐疙,更多文章敬請(qǐng)關(guān)注后續(xù)文章膜楷。版權(quán)歸作者所有,如有轉(zhuǎn)發(fā)贞奋,請(qǐng)注明文章出處:原文鏈接)