Permalink
Browse files

Refactor custom url downloaders. This will allow for the per download…

…er specific enabling/disabling of caching.
  • Loading branch information...
1 parent b21f0d2 commit 7346758524b2ecc0c68fcbd9646e4076f249e607 @koush committed Jan 15, 2013
View
1 UrlImageViewHelper/gen/R.java.d
@@ -1 +0,0 @@
- : /Volumes/Data/src/UrlImageViewHelper/UrlImageViewHelper/bin/AndroidManifest.xml \
View
2 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/Constants.java
@@ -4,7 +4,7 @@
public static final String LOGTAG = "UrlImageViewHelper";
- public static final boolean LOG_ENABLED = false; //set to True to enable verbose logging
+ public static final boolean LOG_ENABLED = true; //set to True to enable verbose logging
//set here and not in Build to maintain proper backwards compatibility
public static final int HONEYCOMB = 11;
View
47 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/ContactContentUrlDownloader.java
@@ -0,0 +1,47 @@
+package com.koushikdutta.urlimageviewhelper;
+
+import java.io.InputStream;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.ContactsContract;
+
+public class ContactContentUrlDownloader implements UrlDownloader {
+ @Override
+ public void download(final Context context, final String url, final String filename, final UrlDownloaderCallback callback, final Runnable completion) {
+ final AsyncTask<Void, Void, Void> downloader = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ try {
+ final ContentResolver cr = context.getContentResolver();
+ InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(cr, Uri.parse(url));
+ callback.onDownloadComplete(ContactContentUrlDownloader.this, is, null);
+ return null;
+ }
+ catch (final Throwable e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(final Void result) {
+ completion.run();
+ }
+ };
+
+ UrlImageViewHelper.executeTask(downloader);
+ }
+
+ @Override
+ public boolean allowCache() {
+ return false;
+ }
+
+ @Override
+ public boolean canDownloadUrl(String url) {
+ return url.startsWith(ContactsContract.Contacts.CONTENT_URI.toString());
+ }
+}
View
46 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/ContentUrlDownloader.java
@@ -0,0 +1,46 @@
+package com.koushikdutta.urlimageviewhelper;
+
+import java.io.InputStream;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+public class ContentUrlDownloader implements UrlDownloader {
+ @Override
+ public void download(final Context context, final String url, final String filename, final UrlDownloaderCallback callback, final Runnable completion) {
+ final AsyncTask<Void, Void, Void> downloader = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ try {
+ final ContentResolver cr = context.getContentResolver();
+ InputStream is = cr.openInputStream(Uri.parse(url));
+ callback.onDownloadComplete(ContentUrlDownloader.this, is, null);
+ return null;
+ }
+ catch (final Throwable e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(final Void result) {
+ completion.run();
+ }
+ };
+
+ UrlImageViewHelper.executeTask(downloader);
+ }
+
+ @Override
+ public boolean allowCache() {
+ return false;
+ }
+
+ @Override
+ public boolean canDownloadUrl(String url) {
+ return url.startsWith(ContentResolver.SCHEME_CONTENT);
+ }
+}
View
43 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/FileUrlDownloader.java
@@ -0,0 +1,43 @@
+package com.koushikdutta.urlimageviewhelper;
+
+import java.io.File;
+import java.net.URI;
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+public class FileUrlDownloader implements UrlDownloader {
+ @Override
+ public void download(final Context context, final String url, final String filename, final UrlDownloaderCallback callback, final Runnable completion) {
+ final AsyncTask<Void, Void, Void> downloader = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ try {
+ callback.onDownloadComplete(FileUrlDownloader.this, null, new File(new URI(url)).getAbsolutePath());
+ return null;
+ }
+ catch (final Throwable e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(final Void result) {
+ completion.run();
+ }
+ };
+
+ UrlImageViewHelper.executeTask(downloader);
+ }
+
+ @Override
+ public boolean allowCache() {
+ return false;
+ }
+
+ @Override
+ public boolean canDownloadUrl(String url) {
+ return url.startsWith("file:/");
+ }
+}
View
89 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/HttpUrlDownloader.java
@@ -0,0 +1,89 @@
+package com.koushikdutta.urlimageviewhelper;
+
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.http.NameValuePair;
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+import com.koushikdutta.urlimageviewhelper.UrlImageViewHelper.RequestPropertiesCallback;
+
+public class HttpUrlDownloader implements UrlDownloader {
+ private RequestPropertiesCallback mRequestPropertiesCallback;
+
+ public RequestPropertiesCallback getRequestPropertiesCallback() {
+ return mRequestPropertiesCallback;
+ }
+
+ public void setRequestPropertiesCallback(final RequestPropertiesCallback callback) {
+ mRequestPropertiesCallback = callback;
+ }
+
+
+ @Override
+ public void download(final Context context, final String url, final String filename, final UrlDownloaderCallback callback, final Runnable completion) {
+ final AsyncTask<Void, Void, Void> downloader = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ try {
+ InputStream is = null;
+
+ String thisUrl = url;
+ HttpURLConnection urlConnection;
+ while (true) {
+ final URL u = new URL(thisUrl);
+ urlConnection = (HttpURLConnection)u.openConnection();
+ urlConnection.setInstanceFollowRedirects(true);
+
+ if (mRequestPropertiesCallback != null) {
+ final ArrayList<NameValuePair> props = mRequestPropertiesCallback.getHeadersForRequest(context, url);
+ if (props != null) {
+ for (final NameValuePair pair: props) {
+ urlConnection.addRequestProperty(pair.getName(), pair.getValue());
+ }
+ }
+ }
+
+ if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_MOVED_TEMP && urlConnection.getResponseCode() != HttpURLConnection.HTTP_MOVED_PERM)
+ break;
+ thisUrl = urlConnection.getHeaderField("Location");
+ }
+
+ if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ UrlImageViewHelper.clog("Response Code: " + urlConnection.getResponseCode());
+ return null;
+ }
+ is = urlConnection.getInputStream();
+ callback.onDownloadComplete(HttpUrlDownloader.this, is, null);
+ return null;
+ }
+ catch (final Throwable e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(final Void result) {
+ completion.run();
+ }
+ };
+
+ UrlImageViewHelper.executeTask(downloader);
+ }
+
+ @Override
+ public boolean allowCache() {
+ return true;
+ }
+
+ @Override
+ public boolean canDownloadUrl(String url) {
+ return url.startsWith("http");
+ }
+}
View
15 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/UrlDownloader.java
@@ -0,0 +1,15 @@
+package com.koushikdutta.urlimageviewhelper;
+
+import java.io.InputStream;
+
+import android.content.Context;
+
+public interface UrlDownloader {
+ public static interface UrlDownloaderCallback {
+ public void onDownloadComplete(UrlDownloader downloader, InputStream in, String filename);
+ }
+
+ public void download(Context context, String url, String filename, UrlDownloaderCallback callback, Runnable completion);
+ public boolean allowCache();
+ public boolean canDownloadUrl(String url);
+}
View
147 UrlImageViewHelper/src/com/koushikdutta/urlimageviewhelper/UrlImageViewHelper.java
@@ -6,8 +6,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
@@ -17,9 +15,7 @@
import org.apache.http.NameValuePair;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.app.ActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
@@ -28,18 +24,16 @@
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Looper;
-import android.provider.ContactsContract;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.widget.ImageView;
import android.view.WindowManager;
+import android.widget.ImageView;
public final class UrlImageViewHelper {
- private static void clog(String format, Object... args) {
+ static void clog(String format, Object... args) {
String log;
if (args.length == 0)
log = format;
@@ -564,11 +558,21 @@ private static void setUrlDrawable(final Context context, final ImageView imageV
final int targetHeight = th <= 0 ? Integer.MAX_VALUE : th;
final Loader loader = new Loader() {
@Override
- public void run() {
+ public void onDownloadComplete(UrlDownloader downloader, InputStream in, String existingFilename) {
try {
+ Assert.assertTrue(in == null || existingFilename == null);
+ if (in == null && existingFilename == null)
+ return;
+ if (in != null) {
+ FileOutputStream fout = new FileOutputStream(filename);
+ copyStream(in, fout);
+ fout.close();
+ }
result = loadDrawableFromStream(context, url, filename, targetWidth, targetHeight);
}
catch (final Exception ex) {
+ if (downloader != null && !downloader.allowCache() && existingFilename == null)
+ new File(filename).delete();
if (Constants.LOG_ENABLED)
Log.e(Constants.LOGTAG, "Error loading " + url, ex);
}
@@ -583,9 +587,10 @@ public void run() {
if (usableResult == null) {
clog("No usable result, defaulting " + url);
usableResult = defaultDrawable;
+ mLiveCache.put(url, usableResult);
}
mPendingDownloads.remove(url);
- mLiveCache.put(url, usableResult);
+// mLiveCache.put(url, usableResult);
if (callback != null && imageView == null)
callback.onLoaded(null, loader.result, url, false);
int waitingCount = 0;
@@ -619,7 +624,7 @@ public void run() {
final AsyncTask<Void, Void, Void> fileloader = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(final Void... params) {
- loader.run();
+ loader.onDownloadComplete(null, null, filename);
return null;
}
@Override
@@ -637,88 +642,37 @@ protected void onPostExecute(final Void result) {
catch (final Exception ex) {
}
}
-
- mDownloader.download(context, url, filename, loader, completion);
+
+ for (UrlDownloader downloader: mDownloaders) {
+ if (downloader.canDownloadUrl(url)) {
+ downloader.download(context, url, filename, loader, completion);
+ return;
+ }
+ }
+
+ imageView.setImageDrawable(defaultDrawable);
}
- private static abstract class Loader implements Runnable {
+ private static abstract class Loader implements UrlDownloader.UrlDownloaderCallback {
Drawable result;
}
-
- public static interface UrlDownloader {
- public void download(Context context, String url, String filename, Runnable loader, Runnable completion);
+
+ private static HttpUrlDownloader mHttpDownloader = new HttpUrlDownloader();
+ private static ContentUrlDownloader mContentDownloader = new ContentUrlDownloader();
+ private static ContactContentUrlDownloader mContactDownloader = new ContactContentUrlDownloader();
+ private static FileUrlDownloader mFileDownloader = new FileUrlDownloader();
+ private static ArrayList<UrlDownloader> mDownloaders = new ArrayList<UrlDownloader>();
+ public static ArrayList<UrlDownloader> getDownloaders() {
+ return mDownloaders;
}
-
- private static UrlDownloader mDefaultDownloader = new UrlDownloader() {
- @Override
- public void download(final Context context, final String url, final String filename, final Runnable loader, final Runnable completion) {
- final AsyncTask<Void, Void, Void> downloader = new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(final Void... params) {
- try {
- InputStream is = null;
- if (url.startsWith(ContentResolver.SCHEME_CONTENT)) {
- final ContentResolver cr = context.getContentResolver();
- if (url.startsWith(ContactsContract.Contacts.CONTENT_URI.toString())) {
- is = ContactsContract.Contacts.openContactPhotoInputStream(cr, Uri.parse(url));
- } else {
- is = cr.openInputStream(Uri.parse(url));
- }
- }
- else {
- String thisUrl = url;
- HttpURLConnection urlConnection;
- while (true) {
- final URL u = new URL(thisUrl);
- urlConnection = (HttpURLConnection)u.openConnection();
- urlConnection.setInstanceFollowRedirects(true);
-
- if (mRequestPropertiesCallback != null) {
- final ArrayList<NameValuePair> props = mRequestPropertiesCallback.getHeadersForRequest(context, url);
- if (props != null) {
- for (final NameValuePair pair: props) {
- urlConnection.addRequestProperty(pair.getName(), pair.getValue());
- }
- }
- }
-
- if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_MOVED_TEMP && urlConnection.getResponseCode() != HttpURLConnection.HTTP_MOVED_PERM)
- break;
- thisUrl = urlConnection.getHeaderField("Location");
- }
-
- if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- clog("Response Code: " + urlConnection.getResponseCode());
- return null;
- }
- is = urlConnection.getInputStream();
- }
-
- if (is != null) {
- final FileOutputStream fos = new FileOutputStream(filename);
- copyStream(is, fos);
- fos.close();
- is.close();
- }
- loader.run();
- return null;
- }
- catch (final Throwable e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(final Void result) {
- completion.run();
- }
- };
-
- executeTask(downloader);
- }
- };
-
+
+ static {
+ mDownloaders.add(mHttpDownloader);
+ mDownloaders.add(mContactDownloader);
+ mDownloaders.add(mContentDownloader);
+ mDownloaders.add(mFileDownloader);
+ }
+
public static interface RequestPropertiesCallback {
public ArrayList<NameValuePair> getHeadersForRequest(Context context, String url);
}
@@ -733,19 +687,6 @@ public static void setRequestPropertiesCallback(final RequestPropertiesCallback
mRequestPropertiesCallback = callback;
}
-
- public static void useDownloader(final UrlDownloader downloader) {
- mDownloader = downloader;
- }
-
- public static void useDefaultDownloader() {
- mDownloader = mDefaultDownloader;
- }
-
- public static UrlDownloader getDefaultDownloader() {
- return mDownloader;
- }
-
private static UrlImageCache mLiveCache = UrlImageCache.getInstance();
private static UrlLruCache mDeadCache;
@@ -787,9 +728,7 @@ public void headshot() {
}
}
- private static UrlDownloader mDownloader = mDefaultDownloader;
-
- private static void executeTask(final AsyncTask<Void, Void, Void> task) {
+ static void executeTask(final AsyncTask<Void, Void, Void> task) {
if (Build.VERSION.SDK_INT < Constants.HONEYCOMB) {
task.execute();
} else {
View
4 UrlImageViewHelperSample/AndroidManifest.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.koushikdutta.test"
+ package="com.koushikdutta.urlimageviewhelper.sample"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name="com.koushikdutta.urlimageviewhelper.sample.UrlImageViewHelperSample"
+ <activity android:name=".UrlImageViewHelperSample"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
View
29 UrlImageViewHelperSample/gen/com/koushikdutta/urlimageviewhelper/R.java
@@ -1,29 +0,0 @@
-/* AUTO-GENERATED FILE. DO NOT MODIFY.
- *
- * This class was automatically generated by the
- * aapt tool from the resource data it found. It
- * should not be modified by hand.
- */
-
-package com.koushikdutta.urlimageviewhelper;
-
-public final class R {
- public static final class attr {
- }
- public static final class drawable {
- public static final int icon=0x7f020000;
- public static final int loading=0x7f020001;
- }
- public static final class id {
- public static final int results=0x7f050002;
- public static final int search=0x7f050001;
- public static final int search_text=0x7f050000;
- }
- public static final class layout {
- public static final int main=0x7f030000;
- }
- public static final class string {
- public static final int app_name=0x7f040001;
- public static final int hello=0x7f040000;
- }
-}
View
2 ...en/com/koushikdutta/test/BuildConfig.java → ...rlimageviewhelper/sample/BuildConfig.java
@@ -1,5 +1,5 @@
/** Automatically generated file. DO NOT MODIFY */
-package com.koushikdutta.test;
+package com.koushikdutta.urlimageviewhelper.sample;
public final class BuildConfig {
public final static boolean DEBUG = true;
View
2 ...erSample/gen/com/koushikdutta/test/R.java → ...hikdutta/urlimageviewhelper/sample/R.java
@@ -5,7 +5,7 @@
* should not be modified by hand.
*/
-package com.koushikdutta.test;
+package com.koushikdutta.urlimageviewhelper.sample;
public final class R {
public static final class attr {
View
1 ...HelperSample/src/com/koushikdutta/urlimageviewhelper/sample/UrlImageViewHelperSample.java
@@ -27,7 +27,6 @@
import android.widget.ListView;
import android.widget.Toast;
-import com.koushikdutta.test.R;
import com.koushikdutta.urlimageviewhelper.UrlImageViewHelper;
public class UrlImageViewHelperSample extends Activity {

0 comments on commit 7346758

Please sign in to comment.