Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

playing around with image loader, add support for thumbnails add abil…

…ity to set the number of tasks
  • Loading branch information...
commit dbffa71a780c78e906df4d1869ba5a3dc63b00cf 1 parent bcd8096
Luigi Agosti luigi-agosti authored
Showing with 1,056 additions and 445 deletions.
  1. +9 −3 core/src/main/java/com/novoda/imageloader/core/bitmap/BitmapUtil.java
  2. +19 −0 core/src/main/java/com/novoda/imageloader/core/file/BasicFileManager.java
  3. +5 −0 core/src/main/java/com/novoda/imageloader/core/file/FileManager.java
  4. +36 −46 core/src/main/java/com/novoda/imageloader/core/loader/ConcurrentLoader.java
  5. +2 −2 core/src/main/java/com/novoda/imageloader/core/loader/Loader.java
  6. +66 −67 core/src/main/java/com/novoda/imageloader/core/loader/SimpleLoader.java
  7. +60 −0 core/src/main/java/com/novoda/imageloader/core/loader/util/AsyncResult.java
  8. +457 −0 core/src/main/java/com/novoda/imageloader/core/loader/util/AsyncTask.java
  9. +19 −19 core/src/main/java/com/novoda/imageloader/core/loader/util/BitmapDisplayer.java
  10. +128 −80 core/src/main/java/com/novoda/imageloader/core/loader/util/LoaderTask.java
  11. +103 −102 core/src/main/java/com/novoda/imageloader/core/loader/util/SingleThreadedLoader.java
  12. +9 −0 core/src/main/java/com/novoda/imageloader/core/model/ImageTag.java
  13. +6 −0 core/src/main/java/com/novoda/imageloader/core/model/ImageTagFactory.java
  14. +10 −0 core/src/main/java/com/novoda/imageloader/core/model/ImageWrapper.java
  15. +2 −2 core/src/main/java/com/novoda/imageloader/core/network/UrlNetworkLoader.java
  16. +1 −2  core/src/test/java/com/novoda/imageloader/core/Util.java
  17. +107 −105 core/src/test/java/com/novoda/imageloader/core/service/CacheCleanerTest.java
  18. +17 −17 core/src/test/java/com/novoda/imageloader/core/util/UrlUtilTest.java
12 core/src/main/java/com/novoda/imageloader/core/bitmap/BitmapUtil.java
View
@@ -42,12 +42,11 @@ public Bitmap decodeFileAndScale(File f, int width, int height) {
return scaleBitmap(unscaledBitmap, width, height);
}
- public Bitmap scaleResourceBitmap(ImageWrapper iw, int resourceId) {
- Context c = iw.getContext();
+ public Bitmap scaleResourceBitmap(Context c, int width, int height, int resourceId) {
Bitmap b = null;
try {
b = BitmapFactory.decodeResource(c.getResources(), resourceId);
- return scaleBitmap(b, iw.getWidth(), iw.getHeight());
+ return scaleBitmap(b, width, height);
} catch (final Throwable e) {
System.gc();
}
@@ -57,6 +56,9 @@ public Bitmap scaleResourceBitmap(ImageWrapper iw, int resourceId) {
public Bitmap scaleBitmap(Bitmap b, int width, int height) {
int imageHeight = b.getHeight();
int imageWidth = b.getWidth();
+ if (imageHeight <= height && imageWidth <= width) {
+ return b;
+ }
int finalWidth = width;
int finalHeight = height;
if (imageHeight > imageWidth) {
@@ -151,4 +153,8 @@ private int calculateScale(final int requiredSize, int widthTmp, int heightTmp)
return scale;
}
+ public Bitmap scaleResourceBitmap(ImageWrapper w, int resId) {
+ return scaleResourceBitmap(w.getContext(), w.getWidth(), w.getHeight(), resId);
+ }
+
}
19 core/src/main/java/com/novoda/imageloader/core/file/BasicFileManager.java
View
@@ -16,6 +16,7 @@
package com.novoda.imageloader.core.file;
import java.io.File;
+import java.io.FileOutputStream;
import com.novoda.imageloader.core.LoaderSettings;
import com.novoda.imageloader.core.network.UrlUtil;
@@ -23,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
public class BasicFileManager implements FileManager {
@@ -52,6 +54,16 @@ public String getFilePath(String imageUrl) {
return null;
}
+ @Override
+ public void saveBitmap(String fileName, Bitmap b, int width, int height) {
+ try {
+ FileOutputStream out = new FileOutputStream(fileName + "-" + width + "x" + height);
+ b.compress(Bitmap.CompressFormat.PNG, 90, out);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
private void sendCacheCleanUpBroadcast(Context context, long expirationPeriod) {
String path = settings.getCacheDir().getAbsolutePath();
Intent i = CacheCleaner.getCleanCacheIntent(path, expirationPeriod);
@@ -72,6 +84,13 @@ public File getFile(String url) {
return new File(settings.getCacheDir(), filename);
}
+ @Override
+ public File getFile(String url, int width, int height) {
+ url = processUrl(url);
+ String filename = String.valueOf(url.hashCode()) + "-" + width + "x" + height;
+ return new File(settings.getCacheDir(), filename);
+ }
+
private String processUrl(String url) {
if (!settings.isQueryIncludedInHash()) {
return url;
5 core/src/main/java/com/novoda/imageloader/core/file/FileManager.java
View
@@ -18,6 +18,7 @@
import java.io.File;
import android.content.Context;
+import android.graphics.Bitmap;
public interface FileManager {
@@ -31,4 +32,8 @@
File getFile(String url);
+ void saveBitmap(String fileName, Bitmap b, int width, int height);
+
+ File getFile(String url, int width, int height);
+
}
82 core/src/main/java/com/novoda/imageloader/core/loader/ConcurrentLoader.java
View
@@ -25,52 +25,42 @@
import com.novoda.imageloader.core.model.ImageWrapper;
public class ConcurrentLoader implements Loader {
+
+ private LoaderContext loaderContext;
+
+ public ConcurrentLoader(LoaderContext loaderContext) {
+ this.loaderContext = loaderContext;
+ }
- private LoaderContext loaderContext;
-
- public ConcurrentLoader(LoaderContext loaderContext) {
- this.loaderContext = loaderContext;
- }
-
- @Override
- public void load(ImageView imageView) {
- ImageWrapper w = new ImageWrapper(imageView);
- if (w.getUrl() == null) {
- Log.w("ImageLoader", "You should never call load if you don't set a ImageTag on the view");
- return;
- }
- try {
- if (loaderContext.getCache().hasBitmap(w.getUrl())) {
- Bitmap b = loaderContext.getCache().get(w.getUrl());
- if (b != null) {
- imageView.setImageBitmap(b);
- return;
- }
- }
- setResource(w, w.getLoadingResourceId());
- if (w.isUseCacheOnly()) {
- return;
- }
- new LoaderTask(imageView, loaderContext).execute();
- } catch (ImageNotFoundException inf) {
- setResource(w, w.getNotFoundResourceId());
- } catch (Throwable t) {
- setResource(w, w.getNotFoundResourceId());
- }
- }
-
- private void setResource(ImageWrapper w, int resId) {
- String key = "resource" + resId + w.getHeight() + w.getHeight();
- if (loaderContext.getResBitmapCache().hasBitmap(key)) {
- Bitmap b = loaderContext.getResBitmapCache().get(key);
- if (b != null) {
- w.setBitmap(b);
- return;
- }
- }
- Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(w, resId);
- loaderContext.getResBitmapCache().put(key, b);
- w.setBitmap(b);
- }
+ @Override
+ public void load(ImageView imageView) {
+ ImageWrapper w = new ImageWrapper(imageView);
+ if(w.getUrl() == null) {
+ Log.w("ImageLoader", "You should never call load if you don't set a ImageTag on the view");
+ return;
+ }
+ try {
+ setResource(w, w.getLoadingResourceId());
+ new LoaderTask(imageView, loaderContext).execute();
+ } catch (ImageNotFoundException inf) {
+ setResource(w, w.getNotFoundResourceId());
+ } catch (Throwable t) {
+ setResource(w, w.getNotFoundResourceId());
+ }
+ }
+
+ private void setResource(ImageWrapper w, int resId) {
+ String key = "resource" + resId + w.getHeight() + w.getHeight();
+ if(loaderContext.getResBitmapCache().hasBitmap(key)) {
+ Bitmap b = loaderContext.getResBitmapCache().get(key);
+ if(b != null) {
+ w.setBitmap(b);
+ return;
+ }
+ }
+ Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(w, resId);
+ loaderContext.getResBitmapCache().put(key, b);
+ w.setBitmap(b);
+ }
}
4 core/src/main/java/com/novoda/imageloader/core/loader/Loader.java
View
@@ -19,6 +19,6 @@
public interface Loader {
- void load(ImageView imageView);
-
+ void load(ImageView imageView);
+
}
133 core/src/main/java/com/novoda/imageloader/core/loader/SimpleLoader.java
View
@@ -28,75 +28,74 @@
public class SimpleLoader implements Loader {
- private LoaderContext loaderContext;
- private SingleThreadedLoader singleThreadedLoader;
+ private LoaderContext loaderContext;
+ private SingleThreadedLoader singleThreadedLoader;
- public SimpleLoader(LoaderContext loaderContext) {
- this.loaderContext = loaderContext;
- this.singleThreadedLoader = new SingleThreadedLoader() {
- @Override
- protected Bitmap loadMissingBitmap(ImageWrapper iw) {
- return getBitmap(iw.getUrl(), iw.getWidth(), iw.getHeight());
- }
+ public SimpleLoader(LoaderContext loaderContext) {
+ this.loaderContext = loaderContext;
+ this.singleThreadedLoader = new SingleThreadedLoader() {
+ @Override
+ protected Bitmap loadMissingBitmap(ImageWrapper iw) {
+ return getBitmap(iw.getUrl(), iw.getWidth(), iw.getHeight());
+ }
+ @Override
+ protected void onBitmapLoaded(ImageWrapper iw, Bitmap bmp) {
+ new BitmapDisplayer(bmp, iw).runOnUiThread();
+ SimpleLoader.this.loaderContext.getCache().put(iw.getUrl(), bmp);
+ }
+ };
+ }
- @Override
- protected void onBitmapLoaded(ImageWrapper iw, Bitmap bmp) {
- new BitmapDisplayer(bmp, iw).runOnUiThread();
- SimpleLoader.this.loaderContext.getCache().put(iw.getUrl(), bmp);
- }
- };
- }
+ @Override
+ public void load(ImageView imageView) {
+ ImageWrapper w = new ImageWrapper(imageView);
+ try {
+ if (loaderContext.getCache().hasBitmap(w.getUrl())) {
+ Bitmap b = loaderContext.getCache().get(w.getUrl());
+ if (b != null) {
+ imageView.setImageBitmap(b);
+ return;
+ }
+ }
+ setResource(w, w.getLoadingResourceId());
+ if(w.isUseCacheOnly()) {
+ return;
+ }
+ singleThreadedLoader.push(w);
+ } catch (ImageNotFoundException inf) {
+ setResource(w, w.getNotFoundResourceId());
+ } catch (Throwable t) {
+ setResource(w, w.getNotFoundResourceId());
+ }
+ }
- @Override
- public void load(ImageView imageView) {
- ImageWrapper w = new ImageWrapper(imageView);
- try {
- if (loaderContext.getCache().hasBitmap(w.getUrl())) {
- Bitmap b = loaderContext.getCache().get(w.getUrl());
- if (b != null) {
- imageView.setImageBitmap(b);
- return;
- }
- }
- setResource(w, w.getLoadingResourceId());
- if (w.isUseCacheOnly()) {
- return;
- }
- singleThreadedLoader.push(w);
- } catch (ImageNotFoundException inf) {
- setResource(w, w.getNotFoundResourceId());
- } catch (Throwable t) {
- setResource(w, w.getNotFoundResourceId());
- }
- }
-
- private Bitmap getBitmap(String url, int width, int height) {
- if (url != null && url.length() >= 0) {
- File f = loaderContext.getFileManager().getFile(url);
- if (f.exists()) {
- Bitmap b = loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
- if (b != null) {
- return b;
- }
- }
- loaderContext.getNetworkManager().retrieveImage(url, f);
- return loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
- }
- return null;
- }
-
- private void setResource(ImageWrapper w, int resId) {
- String key = "resource" + resId + w.getHeight() + w.getHeight();
- if (loaderContext.getResBitmapCache().hasBitmap(key)) {
- Bitmap b = loaderContext.getResBitmapCache().get(key);
- if (b != null) {
- w.setBitmap(b);
- return;
- }
- }
- Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(w, resId);
- loaderContext.getResBitmapCache().put(key, b);
- w.setBitmap(b);
- }
+ private Bitmap getBitmap(String url, int width, int height) {
+ if (url != null && url.length() >= 0) {
+ File f = loaderContext.getFileManager().getFile(url);
+ if (f.exists()) {
+ Bitmap b = loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
+ if (b != null) {
+ return b;
+ }
+ }
+ loaderContext.getNetworkManager().retrieveImage(url, f);
+ return loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
+ }
+ return null;
+ }
+
+ private void setResource(ImageWrapper w, int resId) {
+ String key = "resource" + resId + w.getHeight() + w.getHeight();
+ if(loaderContext.getResBitmapCache().hasBitmap(key)) {
+ Bitmap b = loaderContext.getResBitmapCache().get(key);
+ if(b != null) {
+ w.setBitmap(b);
+ return;
+ }
+ }
+ Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(w, resId);
+ loaderContext.getResBitmapCache().put(key, b);
+ w.setBitmap(b);
+ }
}
60 core/src/main/java/com/novoda/imageloader/core/loader/util/AsyncResult.java
View
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.novoda.imageloader.core.loader.util;
+
+import android.os.Message;
+
+/** @hide */
+public class AsyncResult {
+
+ /*************************** Instance Variables **************************/
+
+ // Expect either exception or result to be null
+ public Object userObj;
+ public Throwable exception;
+ public Object result;
+
+ /***************************** Class Methods *****************************/
+
+ /** Saves and sets m.obj */
+ public static AsyncResult forMessage(Message m, Object r, Throwable ex) {
+ AsyncResult ret;
+
+ ret = new AsyncResult(m.obj, r, ex);
+
+ m.obj = ret;
+
+ return ret;
+ }
+
+ /** Saves and sets m.obj */
+ public static AsyncResult forMessage(Message m) {
+ AsyncResult ret;
+
+ ret = new AsyncResult(m.obj, null, null);
+
+ m.obj = ret;
+
+ return ret;
+ }
+
+ /** please note, this sets m.obj to be this */
+ public AsyncResult(Object uo, Object r, Throwable ex) {
+ userObj = uo;
+ result = r;
+ exception = ex;
+ }
+}
457 core/src/main/java/com/novoda/imageloader/core/loader/util/AsyncTask.java
View
@@ -0,0 +1,457 @@
+/**
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.novoda.imageloader.core.loader.util;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import android.os.Handler;
+import android.os.Message;
+
+/**
+ * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
+ * perform background operations and publish results on the UI thread without
+ * having to manipulate threads and/or handlers.</p>
+ *
+ * <p>An asynchronous task is defined by a computation that runs on a background thread and
+ * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
+ * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
+ * and 4 steps, called <code>begin</code>, <code>doInBackground</code>,
+ * <code>processProgress</code> and <code>end</code>.</p>
+ *
+ * <h2>Usage</h2>
+ * <p>AsyncTask must be subclassed to be used. The subclass will override at least
+ * one method ({@link #doInBackground}), and most often will override a
+ * second one ({@link #onPostExecute}.)</p>
+ *
+ * <p>Here is an example of subclassing:</p>
+ * <pre class="prettyprint">
+ * private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long&gt; {
+ * protected Long doInBackground(URL... urls) {
+ * int count = urls.length;
+ * long totalSize = 0;
+ * for (int i = 0; i < count; i++) {
+ * totalSize += Downloader.downloadFile(urls[i]);
+ * publishProgress((int) ((i / (float) count) * 100));
+ * }
+ * return totalSize;
+ * }
+ *
+ * protected void onProgressUpdate(Integer... progress) {
+ * setProgressPercent(progress[0]);
+ * }
+ *
+ * protected void onPostExecute(Long result) {
+ * showDialog("Downloaded " + result + " bytes");
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Once created, a task is executed very simply:</p>
+ * <pre class="prettyprint">
+ * new DownloadFilesTask().execute(url1, url2, url3);
+ * </pre>
+ *
+ * <h2>AsyncTask's generic types</h2>
+ * <p>The three types used by an asynchronous task are the following:</p>
+ * <ol>
+ * <li><code>Params</code>, the type of the parameters sent to the task upon
+ * execution.</li>
+ * <li><code>Progress</code>, the type of the progress units published during
+ * the background computation.</li>
+ * <li><code>Result</code>, the type of the result of the background
+ * computation.</li>
+ * </ol>
+ * <p>Not all types are always used by an asynchronous task. To mark a type as unused,
+ * simply use the type {@link Void}:</p>
+ * <pre>
+ * private class MyTask extends AsyncTask&lt;Void, Void, Void&gt; { ... }
+ * </pre>
+ *
+ * <h2>The 4 steps</h2>
+ * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
+ * <ol>
+ * <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task
+ * is executed. This step is normally used to setup the task, for instance by
+ * showing a progress bar in the user interface.</li>
+ * <li>{@link #doInBackground}, invoked on the background thread
+ * immediately after {@link #onPreExecute()} finishes executing. This step is used
+ * to perform background computation that can take a long time. The parameters
+ * of the asynchronous task are passed to this step. The result of the computation must
+ * be returned by this step and will be passed back to the last step. This step
+ * can also use {@link #publishProgress} to publish one or more units
+ * of progress. These values are published on the UI thread, in the
+ * {@link #onProgressUpdate} step.</li>
+ * <li>{@link #onProgressUpdate}, invoked on the UI thread after a
+ * call to {@link #publishProgress}. The timing of the execution is
+ * undefined. This method is used to display any form of progress in the user
+ * interface while the background computation is still executing. For instance,
+ * it can be used to animate a progress bar or show logs in a text field.</li>
+ * <li>{@link #onPostExecute}, invoked on the UI thread after the background
+ * computation finishes. The result of the background computation is passed to
+ * this step as a parameter.</li>
+ * </ol>
+ *
+ * <h2>Threading rules</h2>
+ * <p>There are a few threading rules that must be followed for this class to
+ * work properly:</p>
+ * <ul>
+ * <li>The task instance must be created on the UI thread.</li>
+ * <li>{@link #execute} must be invoked on the UI thread.</li>
+ * <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
+ * {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
+ * <li>The task can be executed only once (an exception will be thrown if
+ * a second execution is attempted.)</li>
+ * </ul>
+ */
+public abstract class AsyncTask<Params, Progress, Result> {
+ private static final String LOG_TAG = "AsyncTask";
+
+ private static final int CORE_POOL_SIZE = 6;
+ private static final int MAXIMUM_POOL_SIZE = 6;
+ private static final int KEEP_ALIVE = 6;
+
+
+ private static final BlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>();
+
+ private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
+ }
+ };
+
+ private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
+ MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+
+ private static final int MESSAGE_POST_RESULT = 0x1;
+ private static final int MESSAGE_POST_PROGRESS = 0x2;
+ private static final int MESSAGE_POST_CANCEL = 0x3;
+
+ private static final InternalHandler sHandler = new InternalHandler();
+
+ private final WorkerRunnable<Params, Result> mWorker;
+ private final FutureTask<Result> mFuture;
+
+ private volatile Status mStatus = Status.PENDING;
+
+ /**
+ * Indicates the current status of the task. Each status will be set only once
+ * during the lifetime of a task.
+ */
+ public enum Status {
+ /**
+ * Indicates that the task has not been executed yet.
+ */
+ PENDING,
+ /**
+ * Indicates that the task is running.
+ */
+ RUNNING,
+ /**
+ * Indicates that {@link AsyncTask#onPostExecute} has finished.
+ */
+ FINISHED,
+ }
+
+ /**
+ * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
+ */
+ public AsyncTask() {
+ mWorker = new WorkerRunnable<Params, Result>() {
+ public Result call() throws Exception {
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ return doInBackground(mParams);
+ }
+ };
+
+ mFuture = new FutureTask<Result>(mWorker) {
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void done() {
+ Message message;
+ Result result = null;
+
+ try {
+ result = get();
+ } catch (InterruptedException e) {
+ android.util.Log.w(LOG_TAG, e);
+ } catch (ExecutionException e) {
+ throw new RuntimeException("An error occured while executing doInBackground()",
+ e.getCause());
+ } catch (CancellationException e) {
+ message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
+ new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
+ message.sendToTarget();
+ return;
+ } catch (Throwable t) {
+ throw new RuntimeException("An error occured while executing "
+ + "doInBackground()", t);
+ }
+
+ message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+ new AsyncTaskResult<Result>(AsyncTask.this, result));
+ message.sendToTarget();
+ }
+ };
+ }
+
+ /**
+ * Returns the current status of this task.
+ *
+ * @return The current status.
+ */
+ public final Status getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * Override this method to perform a computation on a background thread. The
+ * specified parameters are the parameters passed to {@link #execute}
+ * by the caller of this task.
+ *
+ * This method can call {@link #publishProgress} to publish updates
+ * on the UI thread.
+ *
+ * @param params The parameters of the task.
+ *
+ * @return A result, defined by the subclass of this task.
+ *
+ * @see #onPreExecute()
+ * @see #onPostExecute
+ * @see #publishProgress
+ */
+ protected abstract Result doInBackground(Params... params);
+
+ /**
+ * Runs on the UI thread before {@link #doInBackground}.
+ *
+ * @see #onPostExecute
+ * @see #doInBackground
+ */
+ protected void onPreExecute() {
+ }
+
+ /**
+ * Runs on the UI thread after {@link #doInBackground}. The
+ * specified result is the value returned by {@link #doInBackground}
+ * or null if the task was cancelled or an exception occured.
+ *
+ * @param result The result of the operation computed by {@link #doInBackground}.
+ *
+ * @see #onPreExecute
+ * @see #doInBackground
+ */
+ protected void onPostExecute(Result result) {
+ }
+
+ /**
+ * Runs on the UI thread after {@link #publishProgress} is invoked.
+ * The specified values are the values passed to {@link #publishProgress}.
+ *
+ * @param values The values indicating progress.
+ *
+ * @see #publishProgress
+ * @see #doInBackground
+ */
+ protected void onProgressUpdate(Progress... values) {
+ }
+
+ /**
+ * Runs on the UI thread after {@link #cancel(boolean)} is invoked.
+ *
+ * @see #cancel(boolean)
+ * @see #isCancelled()
+ */
+ protected void onCancelled() {
+ }
+
+ /**
+ * Returns <tt>true</tt> if this task was cancelled before it completed
+ * normally.
+ *
+ * @return <tt>true</tt> if task was cancelled before it completed
+ *
+ * @see #cancel(boolean)
+ */
+ public final boolean isCancelled() {
+ return mFuture.isCancelled();
+ }
+
+ /**
+ * Attempts to cancel execution of this task. This attempt will
+ * fail if the task has already completed, already been cancelled,
+ * or could not be cancelled for some other reason. If successful,
+ * and this task has not started when <tt>cancel</tt> is called,
+ * this task should never run. If the task has already started,
+ * then the <tt>mayInterruptIfRunning</tt> parameter determines
+ * whether the thread executing this task should be interrupted in
+ * an attempt to stop the task.
+ *
+ * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
+ * task should be interrupted; otherwise, in-progress tasks are allowed
+ * to complete.
+ *
+ * @return <tt>false</tt> if the task could not be cancelled,
+ * typically because it has already completed normally;
+ * <tt>true</tt> otherwise
+ *
+ * @see #isCancelled()
+ * @see #onCancelled()
+ */
+ public final boolean cancel(boolean mayInterruptIfRunning) {
+ return mFuture.cancel(mayInterruptIfRunning);
+ }
+
+ /**
+ * Waits if necessary for the computation to complete, and then
+ * retrieves its result.
+ *
+ * @return The computed result.
+ *
+ * @throws CancellationException If the computation was cancelled.
+ * @throws ExecutionException If the computation threw an exception.
+ * @throws InterruptedException If the current thread was interrupted
+ * while waiting.
+ */
+ public final Result get() throws InterruptedException, ExecutionException {
+ return mFuture.get();
+ }
+
+ /**
+ * Waits if necessary for at most the given time for the computation
+ * to complete, and then retrieves its result.
+ *
+ * @param timeout Time to wait before cancelling the operation.
+ * @param unit The time unit for the timeout.
+ *
+ * @return The computed result.
+ *
+ * @throws CancellationException If the computation was cancelled.
+ * @throws ExecutionException If the computation threw an exception.
+ * @throws InterruptedException If the current thread was interrupted
+ * while waiting.
+ * @throws TimeoutException If the wait timed out.
+ */
+ public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
+ ExecutionException, TimeoutException {
+ return mFuture.get(timeout, unit);
+ }
+
+ /**
+ * Executes the task with the specified parameters. The task returns
+ * itself (this) so that the caller can keep a reference to it.
+ *
+ * This method must be invoked on the UI thread.
+ *
+ * @param params The parameters of the task.
+ *
+ * @return This instance of AsyncTask.
+ *
+ * @throws IllegalStateException If {@link #getStatus()} returns either
+ * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+ */
+ public final AsyncTask<Params, Progress, Result> execute(Params... params) {
+ if (mStatus != Status.PENDING) {
+ switch (mStatus) {
+ case RUNNING:
+ throw new IllegalStateException("Cannot execute task:"
+ + " the task is already running.");
+ case FINISHED:
+ throw new IllegalStateException("Cannot execute task:"
+ + " the task has already been executed "
+ + "(a task can be executed only once)");
+ }
+ }
+
+ mStatus = Status.RUNNING;
+
+ onPreExecute();
+
+ mWorker.mParams = params;
+ sExecutor.execute(mFuture);
+
+ return this;
+ }
+
+ /**
+ * This method can be invoked from {@link #doInBackground} to
+ * publish updates on the UI thread while the background computation is
+ * still running. Each call to this method will trigger the execution of
+ * {@link #onProgressUpdate} on the UI thread.
+ *
+ * @param values The progress values to update the UI with.
+ *
+ * @see #onProgressUpdate
+ * @see #doInBackground
+ */
+ protected final void publishProgress(Progress... values) {
+ sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+ new AsyncTaskResult<Progress>(this, values)).sendToTarget();
+ }
+
+ private void finish(Result result) {
+ if (isCancelled()) result = null;
+ onPostExecute(result);
+ mStatus = Status.FINISHED;
+ }
+
+ private static class InternalHandler extends Handler {
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncTaskResult result = (AsyncTaskResult) msg.obj;
+ switch (msg.what) {
+ case MESSAGE_POST_RESULT:
+ // There is only one result
+ result.mTask.finish(result.mData[0]);
+ break;
+ case MESSAGE_POST_PROGRESS:
+ result.mTask.onProgressUpdate(result.mData);
+ break;
+ case MESSAGE_POST_CANCEL:
+ result.mTask.onCancelled();
+ break;
+ }
+ }
+ }
+
+ private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
+ Params[] mParams;
+ }
+
+ private static class AsyncTaskResult<Data> {
+ @SuppressWarnings("rawtypes")
+ final AsyncTask mTask;
+ final Data[] mData;
+
+ @SuppressWarnings("rawtypes")
+ AsyncTaskResult(AsyncTask task, Data... data) {
+ mTask = task;
+ mData = data;
+ }
+ }
+}
38 core/src/main/java/com/novoda/imageloader/core/loader/util/BitmapDisplayer.java
View
@@ -20,26 +20,26 @@
import com.novoda.imageloader.core.model.ImageWrapper;
public class BitmapDisplayer implements Runnable {
- private Bitmap bitmap;
- private ImageWrapper imageView;
+ private Bitmap bitmap;
+ private ImageWrapper imageView;
- public BitmapDisplayer(Bitmap b, ImageWrapper i) {
- bitmap = b;
- imageView = i;
- }
-
- public void runOnUiThread() {
- imageView.runOnUiThread(this);
- }
+ public BitmapDisplayer(Bitmap b, ImageWrapper i) {
+ bitmap = b;
+ imageView = i;
+ }
+
+ public void runOnUiThread() {
+ imageView.runOnUiThread(this);
+ }
- @Override
- public void run() {
- if (bitmap == null) {
- return;
- }
- if (imageView.isUrlChanged()) {
- return;
- }
- imageView.setBitmap(bitmap);
+ @Override
+ public void run() {
+ if (bitmap == null) {
+ return;
}
+ if(imageView.isUrlChanged()) {
+ return;
+ }
+ imageView.setBitmap(bitmap);
+ }
}
208 core/src/main/java/com/novoda/imageloader/core/loader/util/LoaderTask.java
View
@@ -18,8 +18,8 @@
import java.io.File;
import java.lang.ref.WeakReference;
+import android.content.Context;
import android.graphics.Bitmap;
-import android.os.AsyncTask;
import android.widget.ImageView;
import com.novoda.imageloader.core.LoaderContext;
@@ -28,88 +28,136 @@
public class LoaderTask extends AsyncTask<String, Void, Bitmap> {
- private WeakReference<ImageView> imageViewReference;
- private LoaderContext loaderContext;
- private String url;
+ private WeakReference<ImageView> imageViewReference;
+ private LoaderContext loaderContext;
+ private String url;
+ private boolean saveScaledImage;
+ private boolean useCacheOnly;
+ private int width;
+ private int height;
+ private int notFoundResourceId;
+
+ public LoaderTask(ImageView imageView, LoaderContext loaderContext) {
+ this.imageViewReference = new WeakReference<ImageView>(imageView);
+ this.loaderContext = loaderContext;
+ }
- public LoaderTask(ImageView imageView, LoaderContext loaderContext) {
- this.imageViewReference = new WeakReference<ImageView>(imageView);
- this.loaderContext = loaderContext;
- }
+ @Override
+ protected Bitmap doInBackground(String... arg0) {
+ if (imageViewReference == null) {
+ return null;
+ }
+ ImageView imageView = imageViewReference.get();
+ if (imageView == null) {
+ return null;
+ }
+ ImageWrapper imageWrapper = setAndValidateTagInformation(imageView);
+ if(imageWrapper == null) {
+ return null;
+ }
+ if(hasImageViewUrlChanged(imageView)) {
+ return null;
+ }
+
+ if (loaderContext.getCache().hasBitmap(url)) {
+ Bitmap b = loaderContext.getCache().get(url);
+ if (b != null) {
+ return b;
+ }
+ }
+ File imageFile = getImageFile(imageWrapper);
+ if (!imageFile.exists()) {
+ if(useCacheOnly) {
+ return null;
+ }
+ try {
+ loaderContext.getNetworkManager().retrieveImage(url, imageFile);
+ } catch (ImageNotFoundException inf) {
+ return getNotFoundImage(imageWrapper.getContext());
+ }
+ }
+ if(hasImageViewUrlChanged(imageView)) {
+ return null;
+ }
+ return getImageFromFile(imageFile);
+ }
- @Override
- protected Bitmap doInBackground(String... arg0) {
- if (imageViewReference == null) {
- return null;
- }
- ImageView imageView = imageViewReference.get();
- if (imageView == null) {
- return null;
- }
- ImageWrapper w = new ImageWrapper(imageView);
- url = w.getUrl();
- if (url == null || url.length() <= 0) {
- return null;
- }
- int width = w.getWidth();
- int height = w.getHeight();
- if (!url.equals(new ImageWrapper(imageView).getCurrentUrl())) {
- return null;
- }
- File f = loaderContext.getFileManager().getFile(url);
- if (f.exists()) {
- if (!url.equals(new ImageWrapper(imageView).getCurrentUrl())) {
- return null;
- }
- Bitmap b = loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
- if (b != null) {
- return b;
- }
- }
- try {
- loaderContext.getNetworkManager().retrieveImage(url, f);
- } catch (ImageNotFoundException inf) {
- return getResource(w, w.getNotFoundResourceId());
- }
- if (!url.equals(new ImageWrapper(imageView).getCurrentUrl())) {
- return null;
- }
- return loaderContext.getBitmapUtil().decodeFileAndScale(f, width, height);
- }
+ private Bitmap getImageFromFile(File imageFile) {
+ Bitmap b = loaderContext.getBitmapUtil().decodeFileAndScale(imageFile, width, height);
+ if (b != null && saveScaledImage) {
+ saveScaledImage(imageFile, b);
+ }
+ return b;
+ }
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- if (bitmap == null) {
- return;
- }
- if (isCancelled()) {
- bitmap = null;
- return;
- }
- if (imageViewReference == null) {
- return;
- }
- ImageView imageView = imageViewReference.get();
- if (imageView == null) {
- return;
- }
- if (!url.equals(new ImageWrapper(imageView).getCurrentUrl())) {
- return;
- }
- imageView.setImageBitmap(bitmap);
- }
+ private ImageWrapper setAndValidateTagInformation(ImageView imageView) {
+ ImageWrapper imageWrapper = new ImageWrapper(imageView);
+ url = imageWrapper.getUrl();
+ if (url == null || url.length() <= 0) {
+ return null;
+ }
+ width = imageWrapper.getWidth();
+ height = imageWrapper.getHeight();
+ notFoundResourceId = imageWrapper.getNotFoundResourceId();
+ useCacheOnly = imageWrapper.isUseCacheOnly();
+ return imageWrapper;
+ }
- private Bitmap getResource(ImageWrapper w, int resId) {
- String key = "resource" + resId + w.getHeight() + w.getHeight();
- if (loaderContext.getResBitmapCache().hasBitmap(key)) {
- Bitmap b = loaderContext.getResBitmapCache().get(key);
- if (b != null) {
- return b;
- }
- }
- Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(w, resId);
- loaderContext.getResBitmapCache().put(key, b);
- return b;
- }
+ private void saveScaledImage(File imageFile, Bitmap b) {
+ loaderContext.getFileManager().saveBitmap(imageFile.getAbsolutePath(), b, width, height);
+ }
+ private File getImageFile(ImageWrapper imageWrapper) {
+ File imageFile = null;
+ if(imageWrapper.isSaveThumbnail()) {
+ imageFile = loaderContext.getFileManager().getFile(url, width, height);
+ }
+ if (imageFile == null || !imageFile.exists()) {
+ imageFile = loaderContext.getFileManager().getFile(url);
+ if(imageWrapper.isSaveThumbnail()) {
+ saveScaledImage = true;
+ }
+ }
+ return imageFile;
+ }
+
+ private boolean hasImageViewUrlChanged(ImageView imageView) {
+ return !url.equals(new ImageWrapper(imageView).getCurrentUrl());
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if(bitmap == null) {
+ return;
+ }
+ if (isCancelled()) {
+ bitmap = null;
+ return;
+ }
+ if (imageViewReference == null) {
+ return;
+ }
+ ImageView imageView = imageViewReference.get();
+ if (imageView == null) {
+ return;
+ }
+ if(hasImageViewUrlChanged(imageView)) {
+ return;
+ }
+ imageView.setImageBitmap(bitmap);
+ }
+
+ private Bitmap getNotFoundImage(Context c) {
+ String key = "resource" + notFoundResourceId + width + height;
+ if(loaderContext.getResBitmapCache().hasBitmap(key)) {
+ Bitmap b = loaderContext.getResBitmapCache().get(key);
+ if(b != null) {
+ return b;
+ }
+ }
+ Bitmap b = loaderContext.getBitmapUtil().scaleResourceBitmap(c, width, height, notFoundResourceId);
+ loaderContext.getResBitmapCache().put(key, b);
+ return b;
+ }
+
}
205 core/src/main/java/com/novoda/imageloader/core/loader/util/SingleThreadedLoader.java
View
@@ -28,124 +28,125 @@
public abstract class SingleThreadedLoader {
- private static final String TAG = "ImageLoader";
-
- private BitmapLoader thread = new BitmapLoader();
- private Stack<ImageWrapper> stack = new Stack<ImageWrapper>();
- private List<String> notFoundImages = new ArrayList<String>();
-
- public void push(ImageWrapper image) {
- if (TextUtils.isEmpty(image.getUrl())) {
- return;
- }
- pushOnStack(image);
- startThread();
+ private static final String TAG = "ImageLoader";
+
+ private BitmapLoader thread = new BitmapLoader();
+ private Stack<ImageWrapper> stack = new Stack<ImageWrapper>();
+ private List<String> notFoundImages = new ArrayList<String>();
+
+ public void push(ImageWrapper image) {
+ if (TextUtils.isEmpty(image.getUrl())) {
+ return;
}
+ pushOnStack(image);
+ startThread();
+ }
- public int size() {
- synchronized (stack) {
- return stack.size();
- }
+ public int size() {
+ synchronized (stack) {
+ return stack.size();
}
-
- public ImageWrapper pop() {
- synchronized (stack) {
- try {
- return stack.pop();
- } catch (Exception e) {
- return null;
- }
+ }
+
+ public ImageWrapper pop() {
+ synchronized (stack) {
+ try {
+ return stack.pop();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }
+
+ protected abstract Bitmap loadMissingBitmap(ImageWrapper iw);
+
+ protected abstract void onBitmapLoaded(ImageWrapper iw, Bitmap bmp);
+
+ private void clean(ImageWrapper p) {
+ synchronized (stack) {
+ for (int j = 0; j < stack.size(); j++) {
+ if (stack.get(j).getUrl() != null
+ && stack.get(j).getUrl().equals(p.getUrl())) {
+ stack.remove(j);
+ j--;
}
- }
-
- protected abstract Bitmap loadMissingBitmap(ImageWrapper iw);
+ }
+ }
+ }
- protected abstract void onBitmapLoaded(ImageWrapper iw, Bitmap bmp);
-
- private void clean(ImageWrapper p) {
- synchronized (stack) {
- for (int j = 0; j < stack.size(); j++) {
- if (stack.get(j).getUrl() != null && stack.get(j).getUrl().equals(p.getUrl())) {
- stack.remove(j);
- j--;
- }
- }
- }
+ private void pushOnStack(ImageWrapper p) {
+ synchronized (stack) {
+ stack.push(p);
}
+ }
- private void pushOnStack(ImageWrapper p) {
- synchronized (stack) {
- stack.push(p);
- }
+ private class BitmapLoader extends Thread {
+ boolean isWaiting = false;
+
+ public BitmapLoader() {
+ setPriority(Thread.NORM_PRIORITY - 1);
}
- private class BitmapLoader extends Thread {
- boolean isWaiting = false;
-
- public BitmapLoader() {
- setPriority(Thread.NORM_PRIORITY - 1);
- }
-
- @Override
- public void run() {
- while (true) {
- pauseThreadIfnecessary();
- ImageWrapper image = pop();
- if (image != null) {
- loadAndShowImage(image);
- }
- }
- }
-
- private void pauseThreadIfnecessary() {
- if (size() != 0) {
- return;
- }
- synchronized (thread) {
- try {
- isWaiting = true;
- wait();
- } catch (Exception e) {
- Log.v(TAG, "Pausing the thread error " + e.getMessage());
- }
- }
+ @Override
+ public void run() {
+ while (true) {
+ pauseThreadIfnecessary();
+ ImageWrapper image = pop();
+ if(image != null) {
+ loadAndShowImage(image);
}
+ }
+ }
- private void loadAndShowImage(ImageWrapper iw) {
- try {
- if (iw.isUrlChanged()) {
- return;
- }
- Bitmap bmp = loadMissingBitmap(iw);
- if (bmp == null) {
- clean(iw);
- onBitmapLoaded(iw, bmp);
- return;
- }
- onBitmapLoaded(iw, bmp);
- } catch (ImageNotFoundException inf) {
- notFoundImages.add(iw.getUrl());
- } catch (Throwable e) {
- Log.e(TAG, "Throwable : " + e.getMessage(), e);
- }
+ private void pauseThreadIfnecessary() {
+ if (size() != 0) {
+ return;
+ }
+ synchronized (thread) {
+ try {
+ isWaiting = true;
+ wait();
+ } catch (Exception e) {
+ Log.v(TAG, "Pausing the thread error " + e.getMessage());
}
+ }
}
- private void startThread() {
- if (thread.getState() == Thread.State.NEW) {
- thread.start();
- return;
+ private void loadAndShowImage(ImageWrapper iw) {
+ try {
+ if(iw.isUrlChanged()) {
+ return;
+ }
+ Bitmap bmp = loadMissingBitmap(iw);
+ if (bmp == null) {
+ clean(iw);
+ onBitmapLoaded(iw, bmp);
+ return;
}
- synchronized (thread) {
- if (thread.isWaiting) {
- try {
- thread.isWaiting = false;
- thread.notify();
- } catch (Exception ie) {
- Log.e(TAG, "Check and resume the thread " + ie.getMessage());
- }
- }
+ onBitmapLoaded(iw, bmp);
+ } catch(ImageNotFoundException inf) {
+ notFoundImages.add(iw.getUrl());
+ } catch (Throwable e) {
+ Log.e(TAG, "Throwable : " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private void startThread() {
+ if (thread.getState() == Thread.State.NEW) {
+ thread.start();
+ return;
+ }
+ synchronized (thread) {
+ if (thread.isWaiting) {
+ try {
+ thread.isWaiting = false;
+ thread.notify();
+ } catch (Exception ie) {
+ Log.e(TAG, "Check and resume the thread " + ie.getMessage());
}
+ }
}
+ }
}
9 core/src/main/java/com/novoda/imageloader/core/model/ImageTag.java
View
@@ -23,6 +23,7 @@
private int height;
private int width;
private boolean useOnlyCache;
+ private boolean saveThumbnail;
public ImageTag(String url, int loadingResourceId, int notFoundResourceId, int width, int height) {
this.url = url;
@@ -60,4 +61,12 @@ public void setUseOnlyCache(boolean useOnlyCache) {
this.useOnlyCache = useOnlyCache;
}
+ public boolean isSaveThumbnail() {
+ return saveThumbnail;
+ }
+
+ public void setSaveThumbnail(boolean saveThumbnail) {
+ this.saveThumbnail = saveThumbnail;
+ }
+
}
6 core/src/main/java/com/novoda/imageloader/core/model/ImageTagFactory.java
View
@@ -27,6 +27,7 @@
private int defaultImageResId;
private int errorImageResId;
private boolean useOnlyCache;
+ private boolean saveThumbnail;
public ImageTagFactory(int width, int height, int defaultImageResId) {
this.width = width;
@@ -53,9 +54,14 @@ public void setUseOnlyCache(boolean useOnlyCache) {
this.useOnlyCache = useOnlyCache;
}
+ public void setSaveThumbnail(boolean saveThumbnail) {
+ this.saveThumbnail = saveThumbnail;
+ }
+
public ImageTag build(String url) {
ImageTag it = new ImageTag(url, defaultImageResId, errorImageResId, width, height);
it.setUseOnlyCache(useOnlyCache);
+ it.setSaveThumbnail(saveThumbnail);
return it;
}
10 core/src/main/java/com/novoda/imageloader/core/model/ImageWrapper.java
View
@@ -31,6 +31,7 @@
private int height;
private boolean isUseCacheOnly;
private ImageView imageView;
+ private boolean saveThumbnail;
public ImageWrapper(ImageView imageView) {
this.imageView = imageView;
@@ -44,6 +45,7 @@ public ImageWrapper(ImageView imageView) {
this.isUseCacheOnly = tag.isUseOnlyCache();
this.height = tag.getHeight();
this.width = tag.getWidth();
+ this.saveThumbnail = tag.isSaveThumbnail();
if (notFoundResourceId == 0) {
this.notFoundResourceId = tag.getLoadingResourceId();
}
@@ -99,4 +101,12 @@ public boolean isUseCacheOnly() {
return isUseCacheOnly;
}
+ public boolean isSaveThumbnail() {
+ return saveThumbnail;
+ }
+
+ public void setSaveThumbnail(boolean saveThumbnail) {
+ this.saveThumbnail = saveThumbnail;
+ }
+
}
4 core/src/main/java/com/novoda/imageloader/core/network/UrlNetworkLoader.java
View
@@ -41,7 +41,7 @@ public void retrieveImage(String url, File f) {
InputStream is = null;
OutputStream os = null;
HttpURLConnection conn = null;
- applayChangeonSdkVersion(settings.getSdkVersion());
+ applyChangeonSdkVersion(settings.getSdkVersion());
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(settings.getConnectionTimeout());
@@ -62,7 +62,7 @@ public void retrieveImage(String url, File f) {
}
}
- private void applayChangeonSdkVersion(String sdkVersion) {
+ private void applyChangeonSdkVersion(String sdkVersion) {
if (Integer.parseInt(sdkVersion) < 8) {
System.setProperty("http.keepAlive", "false");
}
3  core/src/test/java/com/novoda/imageloader/core/Util.java
View
@@ -17,6 +17,5 @@
public class Util {
- public static final String FOLDER_FOR_TEST_TMP_FILES = "target/unit-test/tmp";
-
+ public static final String FOLDER_FOR_TEST_TMP_FILES = "target/unit-test/tmp";
}
212 core/src/test/java/com/novoda/imageloader/core/service/CacheCleanerTest.java
View
@@ -38,137 +38,139 @@
public class CacheCleanerTest {
- private static final long EXPIRATION_PERIOD = 1500L;
- private Context context;
- private File cacheDir;
- private CacheCleanerUtil cacheCleaner;
- private File testFile;
- private Intent intent;
-
- @Test
- public void SHOULD_cleanOldFiles_IF_reduceCacheActionIsSet() throws IOException {
- prepareTestFile(System.currentTimeMillis() - EXPIRATION_PERIOD);
- when(intent.hasExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA)).thenReturn(true);
- when(intent.getLongExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA, -1)).thenReturn(EXPIRATION_PERIOD);
-
- cacheCleaner.onReceive(context, intent);
-
- assertFalse(testFile.exists());
- }
+ private static final long EXPIRATION_PERIOD = 1500L;
+ private Context context;
+ private File cacheDir;
+ private CacheCleanerUtil cacheCleaner;
+ private File testFile;
+ private Intent intent;
- @Test
- public void SHOULD_notCleanNewFiles_WHIT_reduceAction() throws IOException {
- prepareTestFile();
- when(intent.hasExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA)).thenReturn(true);
- when(intent.getLongExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA, -1)).thenReturn(EXPIRATION_PERIOD);
+ @Test
+ public void SHOULD_cleanOldFiles_IF_reduceCacheActionIsSet() throws IOException {
+ prepareTestFile(System.currentTimeMillis() - EXPIRATION_PERIOD);
+ when(intent.hasExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA)).thenReturn(true);
+ when(intent.getLongExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA, -1)).thenReturn(
+ EXPIRATION_PERIOD);
- cacheCleaner.onReceive(context, intent);
+ cacheCleaner.onReceive(context, intent);
- assertTrue(testFile.exists());
- }
+ assertFalse(testFile.exists());
+ }
- @Test
- public void SHOULD_cleanUpFilesOnly_IF_theActionIsSet() throws IOException {
- prepareTestFile(System.currentTimeMillis());
- when(intent.getAction()).thenReturn(null);
+ @Test
+ public void SHOULD_notCleanNewFiles_WHIT_reduceAction() throws IOException {
+ prepareTestFile();
+ when(intent.hasExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA)).thenReturn(true);
+ when(intent.getLongExtra(CacheCleaner.EXPIRATION_PERIOD_EXTRA, -1)).thenReturn(
+ EXPIRATION_PERIOD);
- cacheCleaner.onReceive(context, intent);
+ cacheCleaner.onReceive(context, intent);
- assertTrue(testFile.exists());
- }
+ assertTrue(testFile.exists());
+ }
- @Test
- public void SHOULD_cleanUpFilesOnly_IF_theCorrectActionIsSet() throws IOException {
- prepareTestFile(System.currentTimeMillis());
- when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn("wrong action");
+ @Test
+ public void SHOULD_cleanUpFilesOnly_IF_theActionIsSet() throws IOException {
+ prepareTestFile(System.currentTimeMillis());
+ when(intent.getAction()).thenReturn(null);
- cacheCleaner.onReceive(context, intent);
+ cacheCleaner.onReceive(context, intent);
- assertTrue(testFile.exists());
- }
+ assertTrue(testFile.exists());
+ }
- @Test
- public void SHOULD_cleanAllFiles_IF_cleanCacheActionIsSet() throws IOException {
- prepareTestFile();
+ @Test
+ public void SHOULD_cleanUpFilesOnly_IF_theCorrectActionIsSet() throws IOException {
+ prepareTestFile(System.currentTimeMillis());
+ when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn("wrong action");
- cacheCleaner.onReceive(context, intent);
+ cacheCleaner.onReceive(context, intent);
- assertFalse(testFile.exists());
- }
-
- @Test
- public void SHOULD_returnWithoutActions_IF_cacheExtraDirIsNull() {
- prepareTestFile();
- when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(null);
+ assertTrue(testFile.exists());
+ }
- cacheCleaner.onReceive(context, intent);
+ @Test
+ public void SHOULD_cleanAllFiles_IF_cleanCacheActionIsSet() throws IOException {
+ prepareTestFile();
- assertTrue(testFile.exists());
- }
+ cacheCleaner.onReceive(context, intent);
- @Test
- public void SHOULD_returnWithoutActions_IF_cacheDirExtraIsEmpty() {
- prepareTestFile();
- when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn("");
+ assertFalse(testFile.exists());
+ }
- cacheCleaner.onReceive(context, intent);
+ @Test
+ public void SHOULD_returnWithoutActions_IF_cacheExtraDirIsNull() {
+ prepareTestFile();
+ when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(null);
- assertTrue(testFile.exists());
- }
+ cacheCleaner.onReceive(context, intent);
- @Test
- public void SHOULD_returnWithoutActions_IF_cacheDirExtraIsNotSet() {
- prepareTestFile();
- when(intent.hasExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(false);
+ assertTrue(testFile.exists());
+ }
- cacheCleaner.onReceive(context, intent);
+ @Test
+ public void SHOULD_returnWithoutActions_IF_cacheDirExtraIsEmpty() {
+ prepareTestFile();
+ when(intent.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn("");
- assertTrue(testFile.exists());
- }
+ cacheCleaner.onReceive(context, intent);
- @Test
- public void SHOULD_notCrash_ON_IntentNull() {
- try {
- cacheCleaner.onReceive(context, null);
- } catch (Exception e) {
- fail("shouldn't fail on null intent");
- }
- }
+ assertTrue(testFile.exists());
+ }
- @Before
- public void setUp() {
- cacheDir = new File(Util.FOLDER_FOR_TEST_TMP_FILES);
- cacheDir.mkdir();
- cacheCleaner = new CacheCleanerUtil();
- intent = prepareStandardIntent();
- }
+ @Test
+ public void SHOULD_returnWithoutActions_IF_cacheDirExtraIsNotSet() {
+ prepareTestFile();
+ when(intent.hasExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(false);
- @After
- public void tearDown() throws IOException {
- FileUtils.deleteDirectory(cacheDir);
- }
+ cacheCleaner.onReceive(context, intent);
- private Intent prepareStandardIntent() {
- Intent i = Mockito.mock(Intent.class);
- when(i.getAction()).thenReturn(CacheCleaner.CLEAN_CACHE_ACTION);
- when(i.hasExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(true);
- when(i.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(cacheDir.getAbsolutePath());
- return i;
- }
+ assertTrue(testFile.exists());
+ }
- private void prepareTestFile() {
- prepareTestFile(System.currentTimeMillis());
+ @Test
+ public void SHOULD_notCrash_ON_IntentNull() {
+ try {
+ cacheCleaner.onReceive(context, null);
+ } catch (Exception e) {
+ fail("shouldn't fail on null intent");
}
-
- private void prepareTestFile(long lastModified) {
- try {
- testFile = new File(cacheDir, "1.tmp");
- FileUtils.write(testFile, "test1");
- testFile.setLastModified(lastModified);
- assertTrue(testFile.exists());
- } catch (Exception e) {
- fail("Setup of the file for the test failed " + e.getMessage());
- }
+ }
+
+ @Before
+ public void setUp() {
+ cacheDir = new File(Util.FOLDER_FOR_TEST_TMP_FILES);
+ cacheDir.mkdir();
+ cacheCleaner = new CacheCleanerUtil();
+ intent = prepareStandardIntent();
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ FileUtils.deleteDirectory(cacheDir);
+ }
+
+ private Intent prepareStandardIntent() {
+ Intent i = Mockito.mock(Intent.class);
+ when(i.getAction()).thenReturn(CacheCleaner.CLEAN_CACHE_ACTION);
+ when(i.hasExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(true);
+ when(i.getStringExtra(CacheCleaner.CACHE_DIR_EXTRA)).thenReturn(cacheDir.getAbsolutePath());
+ return i;
+ }
+
+ private void prepareTestFile() {
+ prepareTestFile(System.currentTimeMillis());
+ }
+
+ private void prepareTestFile(long lastModified) {
+ try {
+ testFile = new File(cacheDir, "1.tmp");
+ FileUtils.write(testFile, "test1");
+ testFile.setLastModified(lastModified);
+ assertTrue(testFile.exists());
+ } catch (Exception e) {
+ fail("Setup of the file for the test failed " + e.getMessage());
}
+ }
}
34 core/src/test/java/com/novoda/imageloader/core/util/UrlUtilTest.java
View
@@ -22,22 +22,22 @@
import com.novoda.imageloader.core.network.UrlUtil;
public class UrlUtilTest {
-
- private UrlUtil urlUtil = new UrlUtil();
-
- @Test
- public void SHOULD_removeQueryFromUrlReturnNul_WHEN_urlIsNull() {
- assertEquals(null, urlUtil.removeQuery(null));
- }
-
- @Test
- public void SHOULD_removeQueryFromUrlReturnUnmodifiedUrl_WHEN_qeryNotPresent() {
- assertEquals("http://www.google.com", urlUtil.removeQuery("http://www.google.com"));
- }
-
- @Test
- public void SHOULD_removeQueryFromUrl() {
- assertEquals("http://www.google.com", urlUtil.removeQuery("http://www.google.com?q=test"));
- }
+
+ private UrlUtil urlUtil = new UrlUtil();
+
+ @Test
+ public void SHOULD_removeQueryFromUrlReturnNul_WHEN_urlIsNull() {
+ assertEquals(null, urlUtil.removeQuery(null));
+ }
+
+ @Test
+ public void SHOULD_removeQueryFromUrlReturnUnmodifiedUrl_WHEN_qeryNotPresent() {
+ assertEquals("http://www.google.com", urlUtil.removeQuery("http://www.google.com"));
+ }
+
+ @Test
+ public void SHOULD_removeQueryFromUrl() {
+ assertEquals("http://www.google.com", urlUtil.removeQuery("http://www.google.com?q=test"));
+ }
}
Please sign in to comment.
Something went wrong with that request. Please try again.