All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bumptech.glide.RequestManager Maven / Gradle / Ivy

Go to download

A fast and efficient image loading library for Android focused on smooth scrolling.

There is a newer version: 5.0.0-rc01
Show newest version
package com.bumptech.glide;

import static com.bumptech.glide.request.RequestOptions.decodeTypeOf;
import static com.bumptech.glide.request.RequestOptions.diskCacheStrategyOf;
import static com.bumptech.glide.request.RequestOptions.skipMemoryCacheOf;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.manager.ConnectivityMonitor;
import com.bumptech.glide.manager.ConnectivityMonitorFactory;
import com.bumptech.glide.manager.Lifecycle;
import com.bumptech.glide.manager.LifecycleListener;
import com.bumptech.glide.manager.RequestManagerTreeNode;
import com.bumptech.glide.manager.RequestTracker;
import com.bumptech.glide.manager.TargetTracker;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.target.ViewTarget;
import com.bumptech.glide.request.transition.Transition;
import com.bumptech.glide.util.Synthetic;
import com.bumptech.glide.util.Util;
import java.io.File;

/**
 * A class for managing and starting requests for Glide. Can use activity, fragment and connectivity
 * lifecycle events to intelligently stop, start, and restart requests. Retrieve either by
 * instantiating a new object, or to take advantage built in Activity and Fragment lifecycle
 * handling, use the static Glide.load methods with your Fragment or Activity.
 *
 * @see Glide#with(android.app.Activity)
 * @see Glide#with(android.support.v4.app.FragmentActivity)
 * @see Glide#with(android.app.Fragment)
 * @see Glide#with(android.support.v4.app.Fragment)
 * @see Glide#with(Context)
 */
public class RequestManager implements LifecycleListener {
  private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock();
  private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
  private static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
      diskCacheStrategyOf(DiskCacheStrategy.DATA).priority(Priority.LOW)
          .skipMemoryCache(true);

  protected final Glide glide;
  @Synthetic final Lifecycle lifecycle;
  private final RequestTracker requestTracker;
  private final RequestManagerTreeNode treeNode;
  private final TargetTracker targetTracker = new TargetTracker();
  private final Runnable addSelfToLifecycle = new Runnable() {
    @Override
    public void run() {
      lifecycle.addListener(RequestManager.this);
    }
  };
  private final Handler mainHandler = new Handler(Looper.getMainLooper());
  private final ConnectivityMonitor connectivityMonitor;

  @NonNull
  private RequestOptions requestOptions;

  public RequestManager(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
    this(glide, lifecycle, treeNode, new RequestTracker(), glide.getConnectivityMonitorFactory());
  }

  // Our usage is safe here.
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;

    final Context context = glide.getGlideContext().getBaseContext();

    connectivityMonitor =
        factory.build(context, new RequestManagerConnectivityListener(requestTracker));

    // If we're the application level request manager, we may be created on a background thread.
    // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
    // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
    // This should be entirely safe.
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

  protected void setRequestOptions(@NonNull RequestOptions toSet) {
    requestOptions = toSet.clone().autoClone();
  }

  private void updateRequestOptions(RequestOptions toUpdate) {
    requestOptions = requestOptions.apply(toUpdate);
  }

  /**
   * Updates the default {@link RequestOptions} for all loads started with this request manager
   * with the given {@link RequestOptions}.
   *
   * 

The {@link RequestOptions} provided here are applied on top of those provided via {@link * GlideBuilder#setDefaultRequestOptions(RequestOptions)}. If there are conflicts, the options * applied here will win. Note that this method does not mutate options provided to * {@link GlideBuilder#setDefaultRequestOptions(RequestOptions)}. * *

Multiple sets of options can be applied. If there are conflicts the last {@link * RequestOptions} applied will win. * *

The modified options will only be applied to loads started after this method is called. * * @see RequestBuilder#apply(RequestOptions) * * @return This request manager. */ public RequestManager applyDefaultRequestOptions(RequestOptions requestOptions) { updateRequestOptions(requestOptions); return this; } /** * Replaces the default {@link RequestOptions} for all loads started with this request manager * with the given {@link RequestOptions}. * *

The {@link RequestOptions} provided here replace those that have been previously provided * via {@link GlideBuilder#setDefaultRequestOptions(RequestOptions)}, {@link * #setDefaultRequestOptions(RequestOptions)} and {@link * #applyDefaultRequestOptions(RequestOptions)}. * *

Subsequent calls to {@link #applyDefaultRequestOptions(RequestOptions)} will not mutate * the {@link RequestOptions} provided here. Instead the manager will create a clone of these * options and mutate the clone. * * @see #applyDefaultRequestOptions(RequestOptions) * * @return This request manager. */ public RequestManager setDefaultRequestOptions(RequestOptions requestOptions) { setRequestOptions(requestOptions); return this; } /** * @see android.content.ComponentCallbacks2#onTrimMemory(int) * * @deprecated This method is called automatically by Glide's internals and shouldn't be called * externally. */ @Deprecated public void onTrimMemory(int level) { glide.onTrimMemory(level); } /** * @see android.content.ComponentCallbacks2#onLowMemory() * * @deprecated This method is called automatically by Glide's internals and shouldn't be called * externally. */ @Deprecated public void onLowMemory() { glide.onLowMemory(); } /** * Returns true if loads for this {@link RequestManager} are currently paused. * * @see #pauseRequests() * @see #resumeRequests() */ public boolean isPaused() { Util.assertMainThread(); return requestTracker.isPaused(); } /** * Cancels any in progress loads, but does not clear resources of completed loads. * * @see #isPaused() * @see #resumeRequests() */ public void pauseRequests() { Util.assertMainThread(); requestTracker.pauseRequests(); } /** * Performs {@link #pauseRequests()} recursively for all managers that are contextually * descendant to this manager based on the Activity/Fragment hierarchy: * *

    *
  • When pausing on an Activity all attached fragments will also get paused. *
  • When pausing on an attached Fragment all descendant fragments will also get paused. *
  • When pausing on a detached Fragment or the application context only the current * RequestManager is paused. *
* *

Note, on pre-Jelly Bean MR1 calling pause on a Fragment will not cause child fragments to * pause, in this case either call pause on the Activity or use a support Fragment. */ public void pauseRequestsRecursive() { Util.assertMainThread(); pauseRequests(); for (RequestManager requestManager : treeNode.getDescendants()) { requestManager.pauseRequests(); } } /** * Restarts any loads that have not yet completed. * * @see #isPaused() * @see #pauseRequests() */ public void resumeRequests() { Util.assertMainThread(); requestTracker.resumeRequests(); } /** * Performs {@link #resumeRequests()} recursively for all managers that are contextually * descendant to this manager based on the Activity/Fragment hierarchy. The hierarchical semantics * are identical as for {@link #pauseRequestsRecursive()}. */ public void resumeRequestsRecursive() { Util.assertMainThread(); resumeRequests(); for (RequestManager requestManager : treeNode.getDescendants()) { requestManager.resumeRequests(); } } /** * Lifecycle callback that registers for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused * requests. */ @Override public void onStart() { resumeRequests(); targetTracker.onStart(); } /** * Lifecycle callback that unregisters for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads. */ @Override public void onStop() { pauseRequests(); targetTracker.onStop(); } /** * Lifecycle callback that cancels all in progress requests and clears and recycles resources for * all completed requests. */ @Override public void onDestroy() { targetTracker.onDestroy(); for (Target target : targetTracker.getAll()) { clear(target); } targetTracker.clear(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); mainHandler.removeCallbacks(addSelfToLifecycle); glide.unregisterRequestManager(this); } /** * Attempts to always load the resource as a {@link android.graphics.Bitmap}, even if it could * actually be animated. * * @return A new request builder for loading a {@link android.graphics.Bitmap} */ public RequestBuilder asBitmap() { return as(Bitmap.class).apply(DECODE_TYPE_BITMAP); } /** * Attempts to always load the resource as a * {@link com.bumptech.glide.load.resource.gif.GifDrawable}. * *

If the underlying data is not a GIF, this will fail. As a result, this should only be used * if the model represents an animated GIF and the caller wants to interact with the GifDrawable * directly. Normally using just {@link #asDrawable()} is sufficient because it will determine * whether or not the given data represents an animated GIF and return the appropriate {@link * Drawable}, animated or not, automatically.

* * @return A new request builder for loading a * {@link com.bumptech.glide.load.resource.gif.GifDrawable}. */ public RequestBuilder asGif() { return as(GifDrawable.class).apply(DECODE_TYPE_GIF); } /** * Attempts to always load the resource using any registered {@link * com.bumptech.glide.load.ResourceDecoder}s that can decode any subclass of {@link Drawable}. * *

By default, may return either a {@link android.graphics.drawable.BitmapDrawable} or {@link * GifDrawable}, but if additional decoders are registered for other {@link Drawable} subclasses, * any of those subclasses may also be returned.

* * @return A new request builder for loading a {@link Drawable}. */ public RequestBuilder asDrawable() { return as(Drawable.class); } /** * A helper method equivalent to calling {@link #asDrawable()} and then {@link * RequestBuilder#load(Object)} with the given model. * * @return A new request builder for loading a {@link Drawable} using the given model. */ public RequestBuilder load(@Nullable Object model) { return asDrawable().load(model); } /** * Attempts always load the resource into the cache and return the {@link File} containing the * cached source data. * *

This method is designed to work for remote data that is or will be cached using {@link * com.bumptech.glide.load.engine.DiskCacheStrategy#DATA}. As a result, specifying a * {@link com.bumptech.glide.load.engine.DiskCacheStrategy} on this request is generally not * recommended. * * @return A new request builder for downloading content to cache and returning the cache File. */ public RequestBuilder downloadOnly() { return as(File.class).apply(DOWNLOAD_ONLY_OPTIONS); } /** * A helper method equivalent to calling {@link #downloadOnly()} ()} and then {@link * RequestBuilder#load(Object)} with the given model. * * @return A new request builder for loading a {@link Drawable} using the given model. */ public RequestBuilder download(@Nullable Object model) { return downloadOnly().load(model); } /** * Attempts to always load a {@link File} containing the resource, either using a file path * obtained from the media store (for local images/videos), or using Glide's disk cache * (for remote images/videos). * *

For remote content, prefer {@link #downloadOnly()}. * * @return A new request builder for obtaining File paths to content. */ public RequestBuilder asFile() { return as(File.class).apply(skipMemoryCacheOf(true)); } /** * Attempts to load the resource using any registered * {@link com.bumptech.glide.load.ResourceDecoder}s * that can decode the given resource class or any subclass of the given resource class. * * @param resourceClass The resource to decode. * @return A new request builder for loading the given resource class. */ public RequestBuilder as(Class resourceClass) { return new RequestBuilder<>(glide, this, resourceClass); } /** * Cancel any pending loads Glide may have for the view and free any resources that may have been * loaded for the view. * *

Note that this will only work if {@link View#setTag(Object)} is not called on this view * outside of Glide.

* * @param view The view to cancel loads and free resources for. * @throws IllegalArgumentException if an object other than Glide's metadata is put as the view's * tag. * @see #clear(Target) */ public void clear(View view) { clear(new ClearTarget(view)); } /** * Cancel any pending loads Glide may have for the target and free any resources (such as * {@link Bitmap}s) that may have been loaded for the target so they may be reused. * * @param target The Target to cancel loads for. */ public void clear(@Nullable final Target target) { if (target == null) { return; } if (Util.isOnMainThread()) { untrackOrDelegate(target); } else { mainHandler.post(new Runnable() { @Override public void run() { clear(target); } }); } } private void untrackOrDelegate(Target target) { boolean isOwnedByUs = untrack(target); if (!isOwnedByUs) { glide.removeFromManagers(target); } } boolean untrack(Target target) { Request request = target.getRequest(); // If the Target doesn't have a request, it's already been cleared. if (request == null) { return true; } if (requestTracker.clearRemoveAndRecycle(request)) { targetTracker.untrack(target); target.setRequest(null); return true; } else { return false; } } void track(Target target, Request request) { targetTracker.track(target); requestTracker.runRequest(request); } RequestOptions getDefaultRequestOptions() { return requestOptions; } @NonNull TransitionOptions getDefaultTransitionOptions(Class transcodeClass) { return glide.getGlideContext().getDefaultTransitionOptions(transcodeClass); } @Override public String toString() { return super.toString() + "{tracker=" + requestTracker + ", treeNode=" + treeNode + "}"; } private static class RequestManagerConnectivityListener implements ConnectivityMonitor .ConnectivityListener { private final RequestTracker requestTracker; public RequestManagerConnectivityListener(RequestTracker requestTracker) { this.requestTracker = requestTracker; } @Override public void onConnectivityChanged(boolean isConnected) { if (isConnected) { requestTracker.restartRequests(); } } } private static class ClearTarget extends ViewTarget { public ClearTarget(View view) { super(view); } @Override public void onResourceReady(Object resource, Transition transition) { // Do nothing. } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy