Skip to content

Commit 25cafed

Browse files
committed
Issue nostra13#398: Introduced synchronous image loading
New API: ImageLoader.loadImageSync(String, ImageSize, DisplayImageOptions) : Bitmap
1 parent 0422c11 commit 25cafed

File tree

5 files changed

+197
-43
lines changed

5 files changed

+197
-43
lines changed

library/src/com/nostra13/universalimageloader/core/DisplayImageOptions.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public final class DisplayImageOptions {
8282
private final BitmapProcessor postProcessor;
8383
private final BitmapDisplayer displayer;
8484
private final Handler handler;
85+
private final boolean isSyncLoading;
8586

8687
private DisplayImageOptions(Builder builder) {
8788
imageResOnLoading = builder.imageResOnLoading;
@@ -102,6 +103,7 @@ private DisplayImageOptions(Builder builder) {
102103
postProcessor = builder.postProcessor;
103104
displayer = builder.displayer;
104105
handler = builder.handler;
106+
isSyncLoading = builder.isSyncLoading;
105107
}
106108

107109
public boolean shouldShowImageOnLoading() {
@@ -185,7 +187,11 @@ public BitmapDisplayer getDisplayer() {
185187
}
186188

187189
public Handler getHandler() {
188-
return (handler == null ? new Handler() : handler);
190+
return isSyncLoading ? null : (handler == null ? new Handler() : handler);
191+
}
192+
193+
boolean isSyncLoading() {
194+
return isSyncLoading;
189195
}
190196

191197
/**
@@ -212,6 +218,7 @@ public static class Builder {
212218
private BitmapProcessor postProcessor = null;
213219
private BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();
214220
private Handler handler = null;
221+
private boolean isSyncLoading = false;
215222

216223
public Builder() {
217224
decodingOptions.inPurgeable = true;
@@ -428,6 +435,11 @@ public Builder displayer(BitmapDisplayer displayer) {
428435
return this;
429436
}
430437

438+
Builder syncLoading(boolean isSyncLoading) {
439+
this.isSyncLoading = isSyncLoading;
440+
return this;
441+
}
442+
431443
/**
432444
* Sets custom {@linkplain Handler handler} for displaying images and firing {@linkplain ImageLoadingListener
433445
* listener} events.
@@ -457,6 +469,7 @@ public Builder cloneFrom(DisplayImageOptions options) {
457469
postProcessor = options.postProcessor;
458470
displayer = options.displayer;
459471
handler = options.handler;
472+
isSyncLoading = options.isSyncLoading;
460473
return this;
461474
}
462475

library/src/com/nostra13/universalimageloader/core/ImageLoader.java

+108-25
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
import com.nostra13.universalimageloader.cache.disc.DiscCacheAware;
2323
import com.nostra13.universalimageloader.cache.memory.MemoryCacheAware;
2424
import com.nostra13.universalimageloader.core.assist.*;
25-
import com.nostra13.universalimageloader.core.imageaware.ImageNonViewAware;
2625
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
26+
import com.nostra13.universalimageloader.core.imageaware.ImageNonViewAware;
2727
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
2828
import com.nostra13.universalimageloader.utils.ImageSizeUtils;
2929
import com.nostra13.universalimageloader.utils.L;
@@ -140,8 +140,8 @@ public void displayImage(String uri, ImageAware imageAware, ImageLoadingListener
140140
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
141141
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
142142
* which should display image
143-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
144-
* default display image options
143+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
144+
* decoding and displaying. If <b>null</b> - default display image options
145145
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
146146
* configuration} will be used.
147147
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
@@ -158,8 +158,8 @@ public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions
158158
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
159159
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
160160
* which should display image
161-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
162-
* default display image options
161+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
162+
* decoding and displaying. If <b>null</b> - default display image options
163163
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
164164
* configuration} will be used.
165165
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
@@ -206,7 +206,11 @@ public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions
206206
.getLockForUri(uri));
207207
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, options
208208
.getHandler());
209-
engine.submit(displayTask);
209+
if (options.isSyncLoading()) {
210+
displayTask.run();
211+
} else {
212+
engine.submit(displayTask);
213+
}
210214
} else {
211215
bmp = options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
212216
listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
@@ -222,7 +226,11 @@ public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions
222226
.getLockForUri(uri));
223227
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, options
224228
.getHandler());
225-
engine.submit(displayTask);
229+
if (options.isSyncLoading()) {
230+
displayTask.run();
231+
} else {
232+
engine.submit(displayTask);
233+
}
226234
}
227235
}
228236

@@ -247,8 +255,8 @@ public void displayImage(String uri, ImageView imageView) {
247255
*
248256
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
249257
* @param imageView {@link ImageView} which should display image
250-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
251-
* default display image options
258+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
259+
* decoding and displaying. If <b>null</b> - default display image options
252260
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
253261
* configuration} will be used.
254262
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
@@ -281,8 +289,8 @@ public void displayImage(String uri, ImageView imageView, ImageLoadingListener l
281289
*
282290
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
283291
* @param imageView {@link ImageView} which should display image
284-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
285-
* default display image options
292+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
293+
* decoding and displaying. If <b>null</b> - default display image options
286294
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
287295
* configuration} will be used.
288296
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
@@ -314,17 +322,17 @@ public void loadImage(String uri, ImageLoadingListener listener) {
314322
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.<br />
315323
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
316324
*
317-
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
318-
* @param minImageSize Minimal size for {@link Bitmap} which will be returned in
319-
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}. Downloaded image will be decoded
320-
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit larger) than
321-
* incoming minImageSize .
322-
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
323-
* thread.
325+
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
326+
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
327+
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}. Downloaded image will be decoded
328+
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit larger) than
329+
* incoming targetImageSize.
330+
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
331+
* thread.
324332
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
325333
*/
326-
public void loadImage(String uri, ImageSize minImageSize, ImageLoadingListener listener) {
327-
loadImage(uri, minImageSize, null, listener);
334+
public void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {
335+
loadImage(uri, targetImageSize, null, listener);
328336
}
329337

330338
/**
@@ -333,8 +341,8 @@ public void loadImage(String uri, ImageSize minImageSize, ImageLoadingListener l
333341
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
334342
*
335343
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
336-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
337-
* default display image options
344+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
345+
* decoding and displaying. If <b>null</b> - default display image options
338346
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
339347
* configuration} will be used.<br />
340348
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
@@ -354,9 +362,9 @@ public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListe
354362
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
355363
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}. Downloaded image will be decoded
356364
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit larger) than
357-
* incoming minImageSize .
358-
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If <b>null</b> -
359-
* default display image options
365+
* incoming targetImageSize.
366+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
367+
* decoding and displaying. If <b>null</b> - default display image options
360368
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
361369
* configuration} will be used.<br />
362370
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
@@ -377,6 +385,81 @@ public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions
377385
displayImage(uri, imageAware, options, listener);
378386
}
379387

388+
/**
389+
* Loads and decodes image synchronously.<br />
390+
* Default display image options
391+
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
392+
* configuration} will be used.<br />
393+
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
394+
*
395+
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
396+
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
397+
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
398+
*/
399+
public Bitmap loadImageSync(String uri) {
400+
return loadImageSync(uri, null, null);
401+
}
402+
403+
/**
404+
* Loads and decodes image synchronously.<br />
405+
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
406+
*
407+
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
408+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
409+
* decoding and scaling. If <b>null</b> - default display image options
410+
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
411+
* configuration} will be used.
412+
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
413+
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
414+
*/
415+
public Bitmap loadImageSync(String uri, DisplayImageOptions options) {
416+
return loadImageSync(uri, null, options);
417+
}
418+
419+
/**
420+
* Loads and decodes image synchronously.<br />
421+
* Default display image options
422+
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
423+
* configuration} will be used.<br />
424+
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
425+
*
426+
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
427+
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded
428+
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
429+
* larger) than incoming targetImageSize.
430+
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
431+
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
432+
*/
433+
public Bitmap loadImageSync(String uri, ImageSize targetImageSize) {
434+
return loadImageSync(uri, targetImageSize, null);
435+
}
436+
437+
/**
438+
* Loads and decodes image synchronously.<br />
439+
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
440+
*
441+
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
442+
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded
443+
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
444+
* larger) than incoming targetImageSize.
445+
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
446+
* decoding and scaling. If <b>null</b> - default display image options
447+
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
448+
* configuration} will be used.
449+
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
450+
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
451+
*/
452+
public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) {
453+
if (options == null) {
454+
options = configuration.defaultDisplayImageOptions;
455+
}
456+
options = new DisplayImageOptions.Builder().cloneFrom(options).syncLoading(true).build();
457+
458+
SyncImageLoadingListener listener = new SyncImageLoadingListener();
459+
loadImage(uri, targetImageSize, options, listener);
460+
return listener.getLoadedBitmap();
461+
}
462+
380463
/**
381464
* Checks if ImageLoader's configuration was initialized
382465
*

library/src/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java

+27-15
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,11 @@ public void run() {
163163

164164
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
165165
displayBitmapTask.setLoggingEnabled(writeLogs);
166-
handler.post(displayBitmapTask);
166+
if (options.isSyncLoading()) {
167+
displayBitmapTask.run();
168+
} else {
169+
handler.post(displayBitmapTask);
170+
}
167171
}
168172

169173
/** @return true - if task should be interrupted; false - otherwise */
@@ -372,26 +376,34 @@ private void downloadImage(File targetFile) throws IOException {
372376

373377
private void fireFailEvent(final FailType failType, final Throwable failCause) {
374378
if (!Thread.interrupted()) {
375-
handler.post(new Runnable() {
376-
@Override
377-
public void run() {
378-
if (options.shouldShowImageOnFail()) {
379-
imageAware.setImageDrawable(options.getImageOnFail(configuration.resources));
379+
if (options.isSyncLoading()) {
380+
listener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));
381+
} else {
382+
handler.post(new Runnable() {
383+
@Override
384+
public void run() {
385+
if (options.shouldShowImageOnFail()) {
386+
imageAware.setImageDrawable(options.getImageOnFail(configuration.resources));
387+
}
388+
listener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));
380389
}
381-
listener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));
382-
}
383-
});
390+
});
391+
}
384392
}
385393
}
386394

387395
private void fireCancelEvent() {
388396
if (!Thread.interrupted()) {
389-
handler.post(new Runnable() {
390-
@Override
391-
public void run() {
392-
listener.onLoadingCancelled(uri, imageAware.getWrappedView());
393-
}
394-
});
397+
if (options.isSyncLoading()) {
398+
listener.onLoadingCancelled(uri, imageAware.getWrappedView());
399+
} else {
400+
handler.post(new Runnable() {
401+
@Override
402+
public void run() {
403+
listener.onLoadingCancelled(uri, imageAware.getWrappedView());
404+
}
405+
});
406+
}
395407
}
396408
}
397409

library/src/com/nostra13/universalimageloader/core/ProcessAndDisplayImageTask.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class ProcessAndDisplayImageTask implements Runnable {
3838
private final ImageLoadingInfo imageLoadingInfo;
3939
private final Handler handler;
4040

41-
public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, Handler handler) {
41+
public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo,
42+
Handler handler) {
4243
this.engine = engine;
4344
this.bitmap = bitmap;
4445
this.imageLoadingInfo = imageLoadingInfo;
@@ -50,6 +51,12 @@ public void run() {
5051
if (engine.configuration.writeLogs) L.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey);
5152
BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();
5253
final Bitmap processedBitmap = processor.process(bitmap);
53-
handler.post(new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine, LoadedFrom.MEMORY_CACHE));
54+
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine, LoadedFrom.MEMORY_CACHE);
55+
displayBitmapTask.setLoggingEnabled(engine.configuration.writeLogs);
56+
if (imageLoadingInfo.options.isSyncLoading()) {
57+
displayBitmapTask.run();
58+
} else {
59+
handler.post(displayBitmapTask);
60+
}
5461
}
5562
}

0 commit comments

Comments
 (0)