EngineJob.java revision 5f4610b54d517be58105bcf73ce3291ba79f9f40
1package com.bumptech.glide.load.engine;
2
3import android.os.Handler;
4import android.util.Log;
5import com.bumptech.glide.load.Key;
6import com.bumptech.glide.request.ResourceCallback;
7import com.bumptech.glide.util.LogTime;
8
9import java.util.ArrayList;
10import java.util.List;
11
12/**
13 * A class that manages a load by adding and removing callbacks for for the load and notifying callbacks when the
14 * load completes.
15 */
16public class EngineJob implements ResourceCallback {
17    private static final String TAG = "EngineJob";
18    private boolean isCacheable;
19    private final EngineJobListener listener;
20    private Key key;
21    private Handler mainHandler;
22    private List<ResourceCallback> cbs;
23    private ResourceCallback cb;
24    private boolean isCancelled;
25    private boolean isComplete;
26
27    public EngineJob(Key key, Handler mainHandler, boolean isCacheable, EngineJobListener listener) {
28        this.key = key;
29        this.isCacheable = isCacheable;
30        this.listener = listener;
31        this.mainHandler = mainHandler;
32    }
33
34    public void addCallback(ResourceCallback cb) {
35        if (this.cb == null) {
36            this.cb = cb;
37        } else {
38            if (cbs == null) {
39                cbs = new ArrayList<ResourceCallback>(2);
40                cbs.add(this.cb);
41            }
42            cbs.add(cb);
43        }
44    }
45
46    public void removeCallback(ResourceCallback cb) {
47        if (cbs != null) {
48            cbs.remove(cb);
49            if (cbs.size() == 0) {
50                cancel();
51            }
52        } else if (this.cb == cb) {
53            this.cb = null;
54            cancel();
55        }
56    }
57
58    // Exposed for testing.
59    void cancel() {
60        if (isComplete || isCancelled) {
61            return;
62        }
63        isCancelled = true;
64        listener.onEngineJobCancelled(key);
65    }
66
67    // Exposed for testing.
68    boolean isCancelled() {
69        return isCancelled;
70    }
71
72    @Override
73    public void onResourceReady(final Resource resource) {
74        final long start = LogTime.getLogTime();
75        mainHandler.post(new Runnable() {
76            @Override
77            public void run() {
78                if (Log.isLoggable(TAG, Log.VERBOSE)) {
79                    Log.v(TAG, "Posted to main thread in onResourceReady in " + LogTime.getElapsedMillis(start)
80                            + " cancelled: " + isCancelled);
81                }
82                if (isCancelled) {
83                    resource.recycle();
84                    return;
85                }
86                resource.setCacheable(isCacheable);
87                isComplete = true;
88
89                // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
90                // synchronously released by one of the callbacks.
91                resource.acquire(1);
92                listener.onEngineJobComplete(key, resource);
93                if (cbs != null) {
94                    resource.acquire(cbs.size());
95                    for (ResourceCallback cb : cbs) {
96                        cb.onResourceReady(resource);
97                    }
98                } else {
99                    resource.acquire(1);
100                    cb.onResourceReady(resource);
101                }
102                // Our request is complete, so we can release the resource.
103                resource.release();
104                if (Log.isLoggable(TAG, Log.VERBOSE)) {
105                    Log.v(TAG, "Finished resource ready in " + LogTime.getElapsedMillis(start));
106                }
107            }
108        });
109    }
110
111    @Override
112    public void onException(final Exception e) {
113        final long start = LogTime.getLogTime();
114        mainHandler.post(new Runnable() {
115            @Override
116            public void run() {
117                if (Log.isLoggable(TAG, Log.VERBOSE)) {
118                    Log.v(TAG, "posted to main thread in onException in " + LogTime.getElapsedMillis(start)
119                            + " cancelled: " + isCancelled);
120                }
121                if (isCancelled) {
122                    return;
123                }
124                isComplete = true;
125
126                listener.onEngineJobComplete(key, null);
127                if (cbs != null) {
128                    for (ResourceCallback cb : cbs) {
129                        cb.onException(e);
130                    }
131                } else {
132                    cb.onException(e);
133                }
134                if (Log.isLoggable(TAG, Log.VERBOSE)) {
135                    Log.v(TAG, "finished onException in " + LogTime.getElapsedMillis(start));
136                }
137            }
138        });
139    }
140}
141