GenericRequest.java revision 1a0d2f25951a536b465c5b2a1dfa5d3c076de912
1package com.bumptech.glide.request;
2
3import android.content.Context;
4import android.graphics.drawable.Drawable;
5import android.util.Log;
6import android.view.animation.Animation;
7import android.view.animation.AnimationUtils;
8import com.bumptech.glide.Priority;
9import com.bumptech.glide.Resource;
10import com.bumptech.glide.load.ResourceDecoder;
11import com.bumptech.glide.load.ResourceEncoder;
12import com.bumptech.glide.load.Transformation;
13import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
14import com.bumptech.glide.load.engine.Engine;
15import com.bumptech.glide.load.model.ModelLoader;
16import com.bumptech.glide.load.data.DataFetcher;
17import com.bumptech.glide.provider.LoadProvider;
18import com.bumptech.glide.request.target.Target;
19
20import java.io.InputStream;
21
22/**
23 * A {@link Request} that loads a {@link Resource} into a given {@link Target}.
24 *
25 * @param <A> The type of the model that the resource will be loaded from.
26 * @param <T> The type of the data that the resource will be loaded from.
27 * @param <Z> The type of the resource that will be loaded.
28 */
29public class GenericRequest<A, T, Z, R> implements Request, Target.SizeReadyCallback, ResourceCallback {
30    private static final String TAG = "Request";
31
32    private final int placeholderResourceId;
33    private final int errorResourceId;
34    private final Context context;
35    private final Transformation<Z> transformation;
36    private final LoadProvider<A, T, Z, R> loadProvider;
37    private final int animationId;
38    private final RequestCoordinator requestCoordinator;
39    private final A model;
40    private Class<R> transcodeClass;
41    private boolean isMemoryCacheable;
42    private Priority priority;
43    private final Target<R> target;
44    private final RequestListener<A> requestListener;
45    private final float sizeMultiplier;
46    private final Engine engine;
47    private Animation animation;
48    private Drawable placeholderDrawable;
49    private Drawable errorDrawable;
50    private boolean isCancelled;
51    private boolean isError;
52    private boolean loadedFromMemoryCache;
53    private Resource resource;
54    private Engine.LoadStatus loadStatus;
55
56    public GenericRequest(LoadProvider<A, T, Z, R> loadProvider, A model, Context context, Priority priority,
57            Target<R> target, float sizeMultiplier, Drawable placeholderDrawable, int placeholderResourceId,
58            Drawable errorDrawable, int errorResourceId, RequestListener<A> requestListener, int animationId,
59            Animation animation, RequestCoordinator requestCoordinator, Engine engine,
60            Transformation<Z> transformation, Class<R> transcodeClass, boolean isMemoryCacheable) {
61        this.loadProvider = loadProvider;
62        this.model = model;
63        this.context = context;
64        this.priority = priority;
65        this.target = target;
66        this.sizeMultiplier = sizeMultiplier;
67        this.placeholderDrawable = placeholderDrawable;
68        this.placeholderResourceId = placeholderResourceId;
69        this.errorDrawable = errorDrawable;
70        this.errorResourceId = errorResourceId;
71        this.requestListener = requestListener;
72        this.animationId = animationId;
73        this.animation = animation;
74        this.requestCoordinator = requestCoordinator;
75        this.engine = engine;
76        this.transformation = transformation;
77        this.transcodeClass = transcodeClass;
78        this.isMemoryCacheable = isMemoryCacheable;
79
80        // We allow null models by just setting an error drawable. Null models will always have empty providers, we
81        // simply skip our sanity checks in that unusual case.
82        if (model != null) {
83            if (loadProvider.getCacheDecoder() == null) {
84                throw new NullPointerException("CacheDecoder must not be null, try .cacheDecoder(ResouceDecoder)");
85            }
86            if (loadProvider.getSourceDecoder() == null) {
87                throw new NullPointerException("SourceDecoder must not be null, try .imageDecoder(ResourceDecoder) " +
88                        "and/or .videoDecoder()");
89            }
90            if (loadProvider.getEncoder() == null) {
91                throw new NullPointerException("Encoder must not be null, try .encode(ResourceEncoder)");
92            }
93            if (loadProvider.getTranscoder() == null) {
94                throw new NullPointerException("Transcoder must not be null, try .as(Class, ResourceTranscoder)");
95            }
96            if (loadProvider.getModelLoader() == null) {
97                throw new NullPointerException("ModelLoader must not be null, try .using(ModelLoader)");
98            }
99        }
100    }
101
102    @Override
103    public void run() {
104        if (model == null) {
105            onException(null);
106            return;
107        }
108
109        target.getSize(this);
110
111        if (!isComplete() && !isFailed()) {
112            setPlaceHolder();
113        }
114    }
115
116    public void cancel() {
117        isCancelled = true;
118        if (loadStatus != null) {
119            loadStatus.cancel();
120            loadStatus = null;
121        }
122    }
123
124    @Override
125    public void clear() {
126        cancel();
127        setPlaceHolder();
128        if (resource != null) {
129            resource.release();
130            resource = null;
131        }
132    }
133
134    @Override
135    public boolean isComplete() {
136        return resource != null;
137    }
138
139    @Override
140    public boolean isFailed() {
141        return isError;
142    }
143
144    private void setPlaceHolder() {
145        if (!canSetPlaceholder()) return;
146
147        if (placeholderDrawable == null && placeholderResourceId > 0) {
148            placeholderDrawable = context.getResources().getDrawable(placeholderResourceId);
149        }
150        target.setPlaceholder(placeholderDrawable);
151    }
152
153    private void setErrorPlaceholder() {
154        if (!canSetPlaceholder()) return;
155
156        if (errorDrawable == null && errorResourceId > 0) {
157            errorDrawable = context.getResources().getDrawable(errorResourceId);
158        }
159        if (errorDrawable == null) {
160            setPlaceHolder();
161        } else {
162            target.setPlaceholder(errorDrawable);
163        }
164    }
165
166    @Override
167    public void onSizeReady(int width, int height) {
168        if (isCancelled) {
169            return;
170        }
171
172        width = Math.round(sizeMultiplier * width);
173        height = Math.round(sizeMultiplier * height);
174        ResourceDecoder<InputStream, Z> cacheDecoder = loadProvider.getCacheDecoder();
175        ResourceDecoder<T, Z> decoder = loadProvider.getSourceDecoder();
176        ResourceEncoder <Z> encoder = loadProvider.getEncoder();
177        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
178        ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
179
180        final String id = modelLoader.getId(model);
181        final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
182
183        loadedFromMemoryCache = true;
184        loadStatus = engine.load(id, width, height, cacheDecoder, dataFetcher, decoder, transformation,
185                encoder, transcoder, priority, isMemoryCacheable, this);
186        loadedFromMemoryCache = resource != null;
187    }
188
189    private boolean canSetImage() {
190        return requestCoordinator == null || requestCoordinator.canSetImage(this);
191    }
192
193    private boolean canSetPlaceholder() {
194        return requestCoordinator == null || requestCoordinator.canSetPlaceholder(this);
195    }
196
197    private boolean isAnyImageSet() {
198        return requestCoordinator != null && requestCoordinator.isAnyRequestComplete();
199    }
200
201    @Override
202    public void onResourceReady(Resource resource) {
203        if (!canSetImage()) {
204            resource.release();
205            return;
206        }
207        if (resource == null || !transcodeClass.isAssignableFrom(resource.get().getClass())) {
208            if (resource != null) {
209                resource.release();
210            }
211            onException(new Exception("Expected to receive an object of " + transcodeClass + " but instead got " +
212                    (resource != null ? resource.get() : null)));
213            return;
214        }
215        R result = (R) resource.get();
216        target.onResourceReady(result);
217        if (!loadedFromMemoryCache && !isAnyImageSet()) {
218            if (animation == null && animationId > 0) {
219                animation = AnimationUtils.loadAnimation(context, animationId);
220            }
221            if (animation != null) {
222                target.startAnimation(animation);
223            }
224        }
225        if (requestListener != null) {
226            requestListener.onImageReady(model, target, loadedFromMemoryCache, isAnyImageSet());
227        }
228
229        this.resource = resource;
230    }
231
232    @Override
233    public void onException(Exception e) {
234//        if (Log.isLoggable(TAG, Log.DEBUG)) {
235            Log.d(TAG, "load failed", e);
236//        }
237
238        isError = true;
239        setErrorPlaceholder();
240
241        //TODO: what if this is a thumbnail request?
242        if (requestListener != null) {
243            requestListener.onException(e, model, target);
244        }
245    }
246}
247