使用
官方給出的簡單使用的例子:
// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
...
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
GlideApp.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// For a simple image list:
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
GlideApp
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
其中最主要的就是部分就是:
Glide.with(content).load(url).into(imageView)
with()
首先來看with():
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
可以看到有五個重載方法,都調用了RequestManagerRetriever的get(),去擷取一個RequestManagerRetriever的唯一執行個體:
/** The singleton instance of RequestManagerRetriever. */
// 單例模式中的餓漢式
private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
/**
* Retrieves and returns the RequestManagerRetriever singleton.
*/
public static RequestManagerRetriever get() {
return INSTANCE;
}
然後利用擷取到的這個RequestManagerRetriever,調用get():
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}
public RequestManager get(Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(android.app.Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm);
}
}
同樣是五個重載方法,我們來看其中一個:
// 這個fragment是v4包下的Fragment
public RequestManager get(Fragment fragment) {
if (fragment.getActivity() == null) {
// 判斷fragment是否已經加添加到父容器上,如果沒有抛出異常
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread()) {
// 如果是在子線程中,傳回一個由ApplicationContext建構的單例的RequestManager
return get(fragment.getActivity().getApplicationContext());
} else {
// 在主線程中的話,調用supportFragmentGet(),并且入參是目前fragment所在的Activity和FragmentManager
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm);
}
}
繼續進入supportFragmentGet():
RequestManager supportFragmentGet(Context context, final FragmentManager fm) {
// 判斷在目前的FragmentManager中是否已經加入了SupportRequestManagerFragment
SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(TAG);
if (current == null) {
// 判斷緩存中是否有該FragmentManager對應的SupportRequestManagerFragment
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
// 如果都沒有,就建立一個SupportRequestManagerFragment,加入到目前的FragmentManager中
current = new SupportRequestManagerFragment();
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
// 判斷目前的FragmentManager是否有RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// 如果沒有的話,建立一個RequestManager
requestManager = new RequestManager(context, current.getLifecycle());
current.setRequestManager(requestManager);
}
return requestManager;
}
這裡我們來看一下SupportRequestManagerFragment究竟是什麼:
public class SupportRequestManagerFragment extends Fragment {
private RequestManager requestManager;
private final ActivityFragmentLifecycle lifecycle;
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
// For testing only.
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
/**
* Sets the current {@link com.bumptech.glide.RequestManager}.
*
* @param requestManager The manager to set.
*/
public void setRequestManager(RequestManager requestManager) {
this.requestManager = requestManager;
}
ActivityFragmentLifecycle getLifecycle() {
return lifecycle;
}
/**
* Returns the current {@link com.bumptech.glide.RequestManager} or null if none is set.
*/
public RequestManager getRequestManager() {
return requestManager;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
// If an activity is re-created, onLowMemory may be called before a manager is ever set.
// See #329.
if (requestManager != null) {
requestManager.onLowMemory();
}
}
}
代碼很簡單,我們可以看出來SupportRequestManagerFragment建立的時候建立了一個ActivityFragmentLifecycle,用來回調SupportRequestManagerFragment的生命周期事件。
當父容器的生命周期改變的時候,我們目前的這個SupportRequestManagerFragment生命周期也會改變,然後就會回調ActivityFragmentLifecycle對應的方法。
回到上面
requestManager = new RequestManager(context, current.getLifecycle());
,确實這裡就把這個ActivityFragmentLifecycle作為構造函參數遞到了RequestManager中。
至此,我們通過
Glide.with()
擷取了一個RequestManager對象。
生命周期事件的傳遞圖:
load()
load()也有很多重載:
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
public DrawableTypeRequest<File> load(File file) {
return (DrawableTypeRequest<File>) fromFile().load(file);
}
public DrawableTypeRequest<Integer> load(Integer resourceId) {
return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
}
public DrawableTypeRequest<URL> load(URL url) {
return (DrawableTypeRequest<URL>) fromUrl().load(url);
}
public DrawableTypeRequest<byte[]> load(byte[] model) {
return (DrawableTypeRequest<byte[]>) fromBytes().load(model);
}
……
最終都建立了一個DrawableTypeRequest對象,接着進入into()。
into()
/**
* Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees
* any resources Glide may have previously loaded into the view so they may be reused.
*
* @see Glide#clear(android.view.View)
*
* @param view The view to cancel previous loads for and load the new resource into.
* @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
*/
public Target<TranscodeType> into(ImageView view) {
// 判斷是否在主線程
Util.assertMainThread();
if (view == null) {
// 對ImageView判空
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
// 根據scaleType做一些處理
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
進而調用into()的重載:
/**
* Set the target the resource will be loaded into.
*
* @see Glide#clear(com.bumptech.glide.request.target.Target)
*
* @param target The target to load the resource into.
* @return The given 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())");
}
// 擷取改目标之前的請求
Request previous = target.getRequest();
if (previous != null) {
// 如果之前的請求不為空,則清除并且從requestTracker移除
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
// 建立一個Request
Request request = buildRequest(target);
// 給該目标設定Request
target.setRequest(request);
// 将該目标加入生命周期的監聽器集合中
lifecycle.addListener(target);
// 開始發起請求
requestTracker.runRequest(request);
return target;
}
into()的流程圖如下:
接着進入runRequest():
/**
* Starts tracking the given request.
*/
// 開始追蹤該請求
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
// 非暫停狀态,開始請求
request.begin();
} else {
// 否則加入暫停隊列
pendingRequests.add(request);
}
}
進入begin():
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
// 修改狀态
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果尺寸有效,進入onSizeReady()
onSizeReady(overrideWidth, overrideHeight);
} else {
// 尺寸無效,先擷取尺寸
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
// 做真正請求前的準備,比如設定占位圖檔
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
進入onSizeReady():
/**
* A callback method that should never be invoked directly.
*/
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Got null fetcher from model loader"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
其中主要做的一件事情就是調用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) {
// 判斷是否是主線程
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
// 生成一個EngineKey
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
// 從記憶體緩存中擷取EngineResource
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// 從活躍的資源中擷取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
// 擷取Map中擷取已經存在的改key對應的EngineJob
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// 如果以上都不滿足,建立一個該key對應的EngineJob,它的作用是排程DecodeJob,添加,移除資源回調,并notify回調
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
// 建立一個DecodeJob,處理來自緩存或者原始的資源,應用轉換動畫以及transcode。
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);
// 存儲該EngineJob
jobs.put(key, engineJob);
engineJob.addCallback(cb);
// 開啟EngineRunnable
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
// 傳回一個LoadStatus,其中記錄着EngineJob和一個ResourceCallback
return new LoadStatus(cb, engineJob);
}
進入start():
public void start(EngineRunnable engineRunnable) {
this.engineRunnable = engineRunnable;
// diskCacheService是一個線程池,預設的是一個先進先出同時有優先級的線程池FifoPriorityThreadPoolExecutor
future = diskCacheService.submit(engineRunnable);
}
線程池執行EngineRunnable,會調用EngineRunnable的run():
@Override
public void run() {
if (isCancelled) {
// 被取消,直接結束
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
// 被取消時,資源回收
resource.recycle();
}
return;
}
if (resource == null) {
// 失敗處理
onLoadFailed(exception);
} else {
// 成功處理
onLoadComplete(resource);
}
}
進入decode():
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
// 從緩存中擷取
return decodeFromCache();
} else {
// 從真正的來源處擷取
return decodeFromSource();
}
}
decodeFromSource()在一連串函數調用鍊之後會進入DecodeJob的decodeSource():
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
// 加載資源
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
// 解析資源
decoded = decodeFromSourceData(data);
} finally {
// 最終回收資源
fetcher.cleanup();
}
return decoded;
}
進入DataFetcher的loadData(),根據來源的不同有不同的實作,我們這裡看下HttpUrlFetcher,通過一個url擷取資源:
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), /*redirects*/, null /*lastUrl*/);
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl) throws IOException {
// 判斷是否重定向的次數太多
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
// 配置HttpURLConnection
urlConnection = connectionFactory.build(url);
urlConnection.setConnectTimeout();
urlConnection.setReadTimeout();
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
// 開啟網絡連接配接
urlConnection.connect();
if (isCancelled) {
// 如果取消,傳回null
return null;
}
// 擷取響應碼
final int statusCode = urlConnection.getResponseCode();
if (statusCode / == ) {
// 如果成功,從服務端擷取流
stream = urlConnection.getInputStream();
return stream;
} else if (statusCode / == ) {
// 重定向
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 + , url);
} else {
// 如果失敗,抛出異常
if (statusCode == -) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
在decodeFromSourceData()中如果需要磁盤緩存的話,會進行磁盤緩存:
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
接着回到EngineRunnable的run(),進入成功處理的方法:
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
這裡的manager就是一個EngineJob,這裡就回調了EngineJob的onResourceReady():
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
MAIN_THREAD_HANDLER是一個主線程的Handler:
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
用來切換到主線程,給對應的target發送成功或者失敗的消息:
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
進入handleResultOnMainThread():
private void handleResultOnMainThread() {
if (isCancelled) {
// 已經取消,回收資源
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
// 回調ResourceCallback的onResourceReady()
// 在其中對應target會去處理資源
// 比如給ImageView設定下載下傳好的圖檔
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
EngineJob的load()流程圖:
參考:Glide 源碼分析