/** * Pre caches the given set of image urls. We recommend using this method to warm the image cache * before calling {@link CustomEventNativeListener#onNativeAdLoaded}. Doing so will force images * to cache before displaying the ad. */ static void preCacheImages( @NonNull final Context context, @NonNull final List<String> imageUrls, @NonNull final ImageListener imageListener) { final ImageLoader imageLoader = Networking.getImageLoader(context); // These Atomics are only accessed on the main thread. // We use Atomics here so we can change their values while keeping a reference for the inner // class. final AtomicInteger imageCounter = new AtomicInteger(imageUrls.size()); final AtomicBoolean anyFailures = new AtomicBoolean(false); ImageLoader.ImageListener volleyImageListener = new ImageLoader.ImageListener() { @Override public void onResponse( final ImageLoader.ImageContainer imageContainer, final boolean isImmediate) { // Image Loader returns a "default" response immediately. We want to ignore this // unless the image is already cached. if (imageContainer.getBitmap() != null) { final int count = imageCounter.decrementAndGet(); if (count == 0 && !anyFailures.get()) { imageListener.onImagesCached(); } } } @Override public void onErrorResponse(final VolleyError volleyError) { MoPubLog.d("Failed to download a native ads image:", volleyError); boolean anyPreviousErrors = anyFailures.getAndSet(true); imageCounter.decrementAndGet(); if (!anyPreviousErrors) { imageListener.onImagesFailedToCache(NativeErrorCode.IMAGE_DOWNLOAD_FAILURE); } } }; for (String url : imageUrls) { if (TextUtils.isEmpty(url)) { anyFailures.set(true); imageListener.onImagesFailedToCache(NativeErrorCode.IMAGE_DOWNLOAD_FAILURE); return; } imageLoader.get(url, volleyImageListener); } }