Skip to content

Commit

Permalink
Dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuriy Budiyev committed Oct 25, 2017
1 parent 6d0fedd commit f8c032b
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* MIT License
*
* Copyright (c) 2017 Yuriy Budiyev [[email protected]]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.budiyev.android.imageloader;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;

public class EmptyPlaceholderProvider<T> implements PlaceholderProvider<T> {
@NonNull
@Override
public Drawable get(@NonNull Context context, @NonNull T data) {
return new ColorDrawable(Color.TRANSPARENT);
}
}
57 changes: 37 additions & 20 deletions src/main/java/com/budiyev/android/imageloader/ImageLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
Expand All @@ -41,6 +39,7 @@

import java.io.File;
import java.io.FileDescriptor;
import java.util.concurrent.ExecutorService;

/**
* Image loader is a universal tool for loading bitmaps efficiently in Android
Expand All @@ -56,6 +55,7 @@ public final class ImageLoader<T> {
private final ImageCache mMemoryCache;
private final ImageCache mStorageCache;
private final PlaceholderProvider<T> mPlaceholderProvider;
private final ExecutorService mExecutor;
private final boolean mFadeEnabled;
private final long mFadeDuration;

Expand All @@ -65,14 +65,26 @@ public final class ImageLoader<T> {
private ImageLoader(@NonNull Context context, @NonNull BitmapLoader<T> bitmapLoader,
@Nullable BitmapProcessor<T> bitmapProcessor, @Nullable ImageCache memoryCache,
@Nullable ImageCache storageCache, @Nullable PlaceholderProvider<T> placeholderProvider,
boolean fadeEnabled, long fadeDuration) {
@Nullable ExecutorService executor, boolean fadeEnabled, long fadeDuration) {
mContext = context;
mMainThreadHandler = new Handler(context.getMainLooper());
mBitmapLoader = bitmapLoader;
mBitmapProcessor = bitmapProcessor;
mMemoryCache = memoryCache;
mStorageCache = storageCache;
mPlaceholderProvider = placeholderProvider;
if (placeholderProvider != null) {
mPlaceholderProvider = placeholderProvider;
} else {
mPlaceholderProvider = new EmptyPlaceholderProvider<>();
}
if (executor != null) {
mExecutor = executor;
} else {
mExecutor = new ImageLoaderExecutor(Runtime.getRuntime().availableProcessors());
}
if (storageCache instanceof StorageImageCache) {
((StorageImageCache) storageCache).setExecutor(mExecutor);
}
mFadeEnabled = fadeEnabled;
mFadeDuration = fadeDuration;
}
Expand Down Expand Up @@ -213,17 +225,12 @@ private void load(@NonNull DataDescriptor<T> descriptor, @NonNull ImageView view
}
currentAction.cancel();
}
Drawable placeholder;
PlaceholderProvider<T> placeholderProvider = mPlaceholderProvider;
if (placeholderProvider != null) {
placeholder = placeholderProvider.get(mContext, descriptor.getData());
} else {
placeholder = new ColorDrawable(Color.TRANSPARENT);
}
Context context = mContext;
Drawable placeholder = mPlaceholderProvider.get(context, descriptor.getData());
LoadImageAction<T> action =
new LoadImageAction<>(mContext, mMainThreadHandler, mPauseLock, mBitmapLoader,
mBitmapProcessor, mMemoryCache, mStorageCache, mFadeEnabled, mFadeDuration,
callbacks, descriptor, view, placeholder);
new LoadImageAction<>(context, mMainThreadHandler, mExecutor, mPauseLock,
mBitmapLoader, mBitmapProcessor, mMemoryCache, mStorageCache, mFadeEnabled,
mFadeDuration, callbacks, descriptor, view, placeholder);
view.setImageDrawable(new PlaceholderDrawable(placeholder, action));
action.execute();
}
Expand Down Expand Up @@ -308,6 +315,7 @@ public static final class Builder<T> {
private ImageCache mMemoryCache;
private ImageCache mStorageCache;
private PlaceholderProvider<T> mPlaceholderProvider;
private ExecutorService mExecutor;
private boolean mFadeEnabled = true;
private long mFadeDuration = 250L;

Expand Down Expand Up @@ -445,6 +453,17 @@ public Builder<T> placeholder(@Nullable PlaceholderProvider<T> provider) {
return this;
}

/**
* Bitmap processor, processes bitmap before showing it
*
* @see BitmapProcessor
*/
@NonNull
public Builder<T> processor(@Nullable BitmapProcessor<T> processor) {
mBitmapProcessor = processor;
return this;
}

/**
* Whether to enable fade effect for images that isn't cached in memory,
* allows to specify fade effect duration
Expand All @@ -466,13 +485,11 @@ public Builder<T> fade(boolean enabled) {
}

/**
* Bitmap processor, processes bitmap before showing it
*
* @see BitmapProcessor
* Custom executor
*/
@NonNull
public Builder<T> processor(@Nullable BitmapProcessor<T> processor) {
mBitmapProcessor = processor;
public Builder<T> executor(@Nullable ExecutorService executor) {
mExecutor = executor;
return this;
}

Expand All @@ -482,7 +499,7 @@ public Builder<T> processor(@Nullable BitmapProcessor<T> processor) {
@NonNull
public ImageLoader<T> build() {
return new ImageLoader<>(mContext, mBitmapLoader, mBitmapProcessor, mMemoryCache,
mStorageCache, mPlaceholderProvider, mFadeEnabled, mFadeDuration);
mStorageCache, mPlaceholderProvider, mExecutor, mFadeEnabled, mFadeDuration);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,18 @@
import java.util.concurrent.TimeUnit;

final class ImageLoaderExecutor extends ThreadPoolExecutor {
public ImageLoaderExecutor() {
this(1);
}

public ImageLoaderExecutor(int poolSize) {
super(poolSize, poolSize, 0L, TimeUnit.NANOSECONDS, new LinkedBlockingQueue<Runnable>(),
new ImageLoaderThreadFactory());
new ImageLoaderThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
}

@Override
protected void afterExecute(Runnable runnable, Throwable throwable) {
if (throwable == null && runnable instanceof Future<?>) {
Future<?> future = (Future<?>) runnable;
if (future.isDone()) {
protected void afterExecute(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
Future<?> f = (Future<?>) r;
if (f.isDone()) {
try {
future.get();
f.get();
} catch (InterruptedException | CancellationException ignored) {
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,19 @@
import java.util.concurrent.atomic.AtomicInteger;

final class ImageLoaderThreadFactory implements ThreadFactory {
private static final AtomicInteger COUNTER = new AtomicInteger();
private final AtomicInteger mCounter = new AtomicInteger(1);

@NonNull
@Override
public Thread newThread(@NonNull Runnable runnable) {
COUNTER.compareAndSet(Integer.MAX_VALUE, 0);
Thread thread = new Thread(runnable, "ImageLoader thread #" + COUNTER.getAndIncrement());
if (thread.getPriority() != Thread.MIN_PRIORITY) {
thread.setPriority(Thread.MIN_PRIORITY);
public Thread newThread(@NonNull Runnable r) {
mCounter.compareAndSet(Integer.MAX_VALUE, 0);
Thread t = new Thread(r, "ImageLoader thread #" + mCounter.getAndIncrement());
if (t.getPriority() != Thread.MIN_PRIORITY) {
t.setPriority(Thread.MIN_PRIORITY);
}
if (thread.isDaemon()) {
thread.setDaemon(false);
if (t.isDaemon()) {
t.setDaemon(false);
}
return thread;
return t;
}
}
43 changes: 0 additions & 43 deletions src/main/java/com/budiyev/android/imageloader/InternalUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

final class InternalUtils {
private static final String URI_SCHEME_HTTP = "http";
private static final String URI_SCHEME_HTTPS = "https";
private static final String URI_SCHEME_FTP = "ftp";
private static final Lock LOADER_EXECUTOR_LOCK = new ReentrantLock();
private static final Lock CACHE_EXECUTOR_LOCK = new ReentrantLock();
private static volatile ThreadPoolExecutor sImageLoaderExecutor;
private static volatile ThreadPoolExecutor sStorageCacheExecutor;

private InternalUtils() {
}
Expand Down Expand Up @@ -84,40 +77,4 @@ public static void close(@Nullable Closeable closeable) {
} catch (IOException ignored) {
}
}

@NonNull
public static ThreadPoolExecutor getImageLoaderExecutor() {
ThreadPoolExecutor executor = sImageLoaderExecutor;
if (executor == null) {
LOADER_EXECUTOR_LOCK.lock();
try {
executor = sImageLoaderExecutor;
if (executor == null) {
executor = new ImageLoaderExecutor(Runtime.getRuntime().availableProcessors());
sImageLoaderExecutor = executor;
}
} finally {
LOADER_EXECUTOR_LOCK.unlock();
}
}
return executor;
}

@NonNull
public static ThreadPoolExecutor getStorageCacheExecutor() {
ThreadPoolExecutor executor = sStorageCacheExecutor;
if (executor == null) {
CACHE_EXECUTOR_LOCK.lock();
try {
executor = sStorageCacheExecutor;
if (executor == null) {
executor = new ImageLoaderExecutor();
sStorageCacheExecutor = executor;
}
} finally {
CACHE_EXECUTOR_LOCK.unlock();
}
}
return executor;
}
}
16 changes: 10 additions & 6 deletions src/main/java/com/budiyev/android/imageloader/LoadImageAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
Expand All @@ -43,6 +44,7 @@
final class LoadImageAction<T> {
private final Context mContext;
private final Handler mMainThreadHandler;
private final ExecutorService mExecutor;
private final PauseLock mPauseLock;
private final BitmapLoader<T> mBitmapLoader;
private final BitmapProcessor<T> mBitmapProcessor;
Expand All @@ -58,13 +60,15 @@ final class LoadImageAction<T> {
private volatile boolean mCancelled;

public LoadImageAction(@NonNull Context context, @NonNull Handler mainThreadHandler,
@NonNull PauseLock pauseLock, @NonNull BitmapLoader<T> bitmapLoader,
@Nullable BitmapProcessor<T> bitmapProcessor, @Nullable ImageCache memoryImageCache,
@Nullable ImageCache storageImageCache, boolean fadeEnabled, long fadeDuration,
@Nullable Callbacks<T> callbacks, @NonNull DataDescriptor<T> descriptor,
@NonNull ImageView view, @NonNull Drawable placeholder) {
@NonNull ExecutorService executor, @NonNull PauseLock pauseLock,
@NonNull BitmapLoader<T> bitmapLoader, @Nullable BitmapProcessor<T> bitmapProcessor,
@Nullable ImageCache memoryImageCache, @Nullable ImageCache storageImageCache,
boolean fadeEnabled, long fadeDuration, @Nullable Callbacks<T> callbacks,
@NonNull DataDescriptor<T> descriptor, @NonNull ImageView view,
@NonNull Drawable placeholder) {
mContext = context;
mMainThreadHandler = mainThreadHandler;
mExecutor = executor;
mPauseLock = pauseLock;
mBitmapLoader = bitmapLoader;
mBitmapProcessor = bitmapProcessor;
Expand All @@ -82,7 +86,7 @@ public void execute() {
if (mCancelled) {
return;
}
mFuture = InternalUtils.getImageLoaderExecutor().submit(new LoadImageTask());
mFuture = mExecutor.submit(new LoadImageTask());
}

public boolean hasSameDescriptor(@NonNull String descriptorKey) {
Expand Down
Loading

0 comments on commit f8c032b

Please sign in to comment.