22
22
import android .util .Log ;
23
23
import androidx .annotation .Nullable ;
24
24
import com .google .android .gms .tasks .Task ;
25
- import com .google .android .gms .tasks .Tasks ;
25
+ import com .google .android .gms .tasks .TaskCompletionSource ;
26
26
import com .google .common .io .ByteStreams ;
27
- import com .google .common .io .Closeables ;
28
27
import java .io .Closeable ;
29
28
import java .io .IOException ;
30
29
import java .io .InputStream ;
31
30
import java .net .MalformedURLException ;
32
31
import java .net .URL ;
33
32
import java .net .URLConnection ;
34
- import java .util .concurrent .Executor ;
33
+ import java .util .concurrent .ExecutorService ;
34
+ import java .util .concurrent .Future ;
35
35
36
- /** Abstraction around downloading an image in a background executor. */
37
- class ImageDownload implements Closeable {
36
+ /**
37
+ * Abstraction around downloading an image in a background executor.
38
+ *
39
+ * @hide
40
+ */
41
+ public class ImageDownload implements Closeable {
38
42
39
43
/** Maximum image size to download in bytes (1 MiB). */
40
44
private static final int MAX_IMAGE_SIZE_BYTES = 1024 * 1024 ;
41
45
42
46
private final URL url ;
47
+ @ Nullable private volatile Future <?> future ;
43
48
@ Nullable private Task <Bitmap > task ;
44
- @ Nullable private volatile InputStream connectionInputStream ;
45
49
46
50
@ Nullable
47
51
public static ImageDownload create (String imageUrl ) {
@@ -60,16 +64,29 @@ private ImageDownload(URL url) {
60
64
this .url = url ;
61
65
}
62
66
63
- public void start (Executor executor ) {
64
- task = Tasks .call (executor , this ::blockingDownload );
67
+ public void start (ExecutorService executor ) {
68
+ TaskCompletionSource <Bitmap > taskCompletionSource = new TaskCompletionSource <>();
69
+ future =
70
+ executor .submit (
71
+ () -> {
72
+ try {
73
+ Bitmap bitmap = blockingDownload ();
74
+ taskCompletionSource .setResult (bitmap );
75
+ } catch (Exception e ) {
76
+ taskCompletionSource .setException (e );
77
+ }
78
+ });
79
+ task = taskCompletionSource .getTask ();
65
80
}
66
81
67
82
public Task <Bitmap > getTask () {
68
83
return checkNotNull (task ); // will throw if getTask() is called without a call to start()
69
84
}
70
85
71
86
public Bitmap blockingDownload () throws IOException {
72
- Log .i (TAG , "Starting download of: " + url );
87
+ if (Log .isLoggable (TAG , Log .INFO )) {
88
+ Log .i (TAG , "Starting download of: " + url );
89
+ }
73
90
74
91
byte [] imageBytes = blockingDownloadBytes ();
75
92
Bitmap bitmap = BitmapFactory .decodeByteArray (imageBytes , /* offset= */ 0 , imageBytes .length );
@@ -96,9 +113,6 @@ private byte[] blockingDownloadBytes() throws IOException {
96
113
// Now actually try to download the content
97
114
byte [] bytes ;
98
115
try (InputStream connectionInputStream = connection .getInputStream ()) {
99
- // Save to a field so that it can be closed on timeout
100
- this .connectionInputStream = connectionInputStream ;
101
-
102
116
// Read one byte over the limit so we can tell if the data is too big, as in many cases
103
117
// BitmapFactory will happily decode a partial image.
104
118
bytes =
@@ -118,14 +132,6 @@ private byte[] blockingDownloadBytes() throws IOException {
118
132
119
133
@ Override
120
134
public void close () {
121
- // Close the stream to prevent downloaded any additional data. This will cause the input stream
122
- // to throw an IOException on read, which will finish the task.
123
- try {
124
- Closeables .closeQuietly (connectionInputStream );
125
- } catch (NullPointerException npe ) {
126
- // Older versions of okio don't handle closing on a different thread than the one that it was
127
- // started on, so just catch it for now.
128
- Log .e (TAG , "Failed to close the image download stream." , npe );
129
- }
135
+ future .cancel (true );
130
136
}
131
137
}
0 commit comments