package com.koushikdutta.urlimageviewhelper; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Context; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.Matrix; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; import android.os.Environment; import android.os.Looper; import android.util.DisplayMetrics; import android.util.Log; import android.view.WindowManager; import android.widget.ImageView; import org.apache.http.NameValuePair; import com.hupu.games.common.HupuLog; import java.io.*; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; public final class UrlImageViewHelper { static void clog(String format, Object... args) { String log; if (args.length == 0) log = format; else log = String.format(format, args); if (Constants.LOG_ENABLED) Log.i(Constants.LOGTAG, log); } public static int copyStream(final InputStream input, final OutputStream output) throws IOException { final byte[] stuff = new byte[8192]; int read; int total = 0; while ((read = input.read(stuff)) != -1) { output.write(stuff, 0, read); total += read; } return total; } static Resources mResources; static DisplayMetrics mMetrics; private static void prepareResources(final Context context) { if (mMetrics != null) { return; } mMetrics = new DisplayMetrics(); // final Activity act = (Activity)context; // act.getWindowManager().getDefaultDisplay().getMetrics(mMetrics); ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay().getMetrics(mMetrics); final AssetManager mgr = context.getAssets(); mResources = new Resources(mgr, mMetrics, context.getResources() .getConfiguration()); } private static boolean mUseBitmapScaling = true; /** * Bitmap scaling will use smart/sane values to limit the maximum dimension * of the bitmap during decode. This will prevent any dimension of the * bitmap from being larger than the dimensions of the device itself. Doing * this will conserve memory. * * @param useBitmapScaling * Toggle for smart resizing. */ public static void setUseBitmapScaling(boolean useBitmapScaling) { mUseBitmapScaling = useBitmapScaling; } /** * Bitmap scaling will use smart/sane values to limit the maximum dimension * of the bitmap during decode. This will prevent any dimension of the * bitmap from being larger than the dimensions of the device itself. Doing * this will conserve memory. */ public static boolean getUseBitmapScaling() { return mUseBitmapScaling; } private static Bitmap loadBitmapFromStream(final Context context, final String url, final String filename, final int targetWidth, final int targetHeight) { prepareResources(context); // Log.v(Constants.LOGTAG,targetWidth); // Log.v(Constants.LOGTAG,targetHeight); InputStream stream = null; // clog("Decoding: " + url + " " + filename); try { BitmapFactory.Options o = null; if (mUseBitmapScaling) { o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; stream = new BufferedInputStream(new FileInputStream(filename), 8192); BitmapFactory.decodeStream(stream, null, o); stream.close(); int scale = 0; while ((o.outWidth >> scale) > targetWidth || (o.outHeight >> scale) > targetHeight) { scale++; } o = new Options(); o.inSampleSize = 1 << scale; } stream = new BufferedInputStream(new FileInputStream(filename), 8192); final Bitmap bitmap = BitmapFactory.decodeStream(stream, null, o); // clog(String.format("Loaded bitmap (%dx%d).", bitmap.getWidth(), // bitmap.getHeight())); return bitmap; } catch (final IOException e) { return null; } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { Log.w(Constants.LOGTAG, "Failed to close FileInputStream", e); } } } } public static final int CACHE_DURATION_INFINITE = Integer.MAX_VALUE; public static final int CACHE_DURATION_ONE_DAY = 1000 * 60 * 60 * 24; public static final int CACHE_DURATION_TWO_DAYS = CACHE_DURATION_ONE_DAY * 2; public static final int CACHE_DURATION_THREE_DAYS = CACHE_DURATION_ONE_DAY * 3; public static final int CACHE_DURATION_FOUR_DAYS = CACHE_DURATION_ONE_DAY * 4; public static final int CACHE_DURATION_FIVE_DAYS = CACHE_DURATION_ONE_DAY * 5; public static final int CACHE_DURATION_SIX_DAYS = CACHE_DURATION_ONE_DAY * 6; public static final int CACHE_DURATION_ONE_WEEK = CACHE_DURATION_ONE_DAY * 7; /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. */ public static void setUrlDrawable(final ImageView imageView, final String url, final int defaultResource) { setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, CACHE_DURATION_THREE_DAYS); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView} once it finishes loading. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. */ public static void setUrlDrawable(final ImageView imageView, final String url) { setUrlDrawable(imageView.getContext(), imageView, url, null, CACHE_DURATION_THREE_DAYS, null); } public static void loadUrlDrawable(final Context context, final String url) { setUrlDrawable(context, null, url, null, CACHE_DURATION_THREE_DAYS, null); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultDrawable * A {@link Drawable} that should be displayed in * {@code imageView} while the image has not been loaded. This * image will also be displayed if the image fails to load. This * can be set to {@code null}. */ public static void setUrlDrawable(final ImageView imageView, final String url, final Drawable defaultDrawable) { setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, CACHE_DURATION_THREE_DAYS, null); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. */ public static void setUrlDrawable(final ImageView imageView, final String url, final int defaultResource, final long cacheDurationMs) { setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, cacheDurationMs); } public static void loadUrlDrawable(final Context context, final String url, final long cacheDurationMs) { setUrlDrawable(context, null, url, null, cacheDurationMs, null); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultDrawable * A {@link Drawable} that should be displayed in * {@code imageView} while the image has not been loaded. This * image will also be displayed if the image fails to load. This * can be set to {@code null}. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. */ public static void setUrlDrawable(final ImageView imageView, final String url, final Drawable defaultDrawable, final long cacheDurationMs) { setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, cacheDurationMs, null); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param context * A {@link Context} to allow setUrlDrawable to load and save * files. * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. */ private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, final int defaultResource, final long cacheDurationMs) { Drawable d = null; if (defaultResource != 0) { d = imageView.getResources().getDrawable(defaultResource); } setUrlDrawable(context, imageView, url, d, cacheDurationMs, null); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ public static void setUrlDrawable(final ImageView imageView, final String url, final int defaultResource, final UrlImageViewCallback callback) { setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, CACHE_DURATION_THREE_DAYS, callback); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ public static void setUrlDrawable(final ImageView imageView, final String url, final UrlImageViewCallback callback) { setUrlDrawable(imageView.getContext(), imageView, url, null, CACHE_DURATION_THREE_DAYS, callback); } public static void loadUrlDrawable(final Context context, final String url, final UrlImageViewCallback callback) { setUrlDrawable(context, null, url, null, CACHE_DURATION_THREE_DAYS, callback); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultDrawable * A {@link Drawable} that should be displayed in * {@code imageView} while the image has not been loaded. This * image will also be displayed if the image fails to load. This * can be set to {@code null}. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ public static void setUrlDrawable(final ImageView imageView, final String url, final Drawable defaultDrawable, final UrlImageViewCallback callback) { setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, CACHE_DURATION_THREE_DAYS, callback); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ public static void setUrlDrawable(final ImageView imageView, final String url, final int defaultResource, final long cacheDurationMs, final UrlImageViewCallback callback) { setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, cacheDurationMs, callback); } public static void loadUrlDrawable(final Context context, final String url, final long cacheDurationMs, final UrlImageViewCallback callback) { setUrlDrawable(context, null, url, null, cacheDurationMs, callback); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultDrawable * A {@link Drawable} that should be displayed in * {@code imageView} while the image has not been loaded. This * image will also be displayed if the image fails to load. This * can be set to {@code null}. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ public static void setUrlDrawable(final ImageView imageView, final String url, final Drawable defaultDrawable, final long cacheDurationMs, final UrlImageViewCallback callback) { setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, cacheDurationMs, callback); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param context * A {@link Context} to allow setUrlDrawable to load and save * files. * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultResource * The Android resid of the {@link Drawable} that should be * displayed while the image is being downloaded. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, final int defaultResource, final long cacheDurationMs, final UrlImageViewCallback callback) { Drawable d = null; if (defaultResource != 0) { d = imageView.getResources().getDrawable(defaultResource); } setUrlDrawable(context, imageView, url, d, cacheDurationMs, callback); } private static boolean isNullOrEmpty(final CharSequence s) { return (s == null || s.equals("") || s.equals("null") || s .equals("NULL")); } private static boolean mHasCleaned = false; public static String getFilenameForUrl(final String url) { return url.hashCode() + ".urlimage"; } /** * Clear out cached images. * * @param context * @param age * The max age of a file. Files older than this age will be * removed. */ public static void cleanup(final Context context, long age) { if (mHasCleaned) { return; } mHasCleaned = true; try { // purge any *.urlimage files over a week old // final String[] files = context.getFilesDir().list(); //add by peter final String[] files = new File(getCahePath(context)).list(); if (files == null) { return; } for (final String file : files) { if (!file.endsWith(".urlimage")) { continue; } // final File f = new File(context.getFilesDir().getAbsolutePath() // + '/' + file); final File f = new File(getCahePath(context)+ File.separator + file); if (System.currentTimeMillis() > f.lastModified() + age) { f.delete(); } } } catch (final Exception e) { e.printStackTrace(); } } /** * Clear out all cached images older than a week. The same as calling * cleanup(context, CACHE_DURATION_ONE_WEEK); * * @param context */ public static void cleanup(final Context context) { cleanup(context, CACHE_DURATION_ONE_WEEK); } private static boolean checkCacheDuration(File file, long cacheDurationMs) { return cacheDurationMs == CACHE_DURATION_INFINITE || System.currentTimeMillis() < file.lastModified() + cacheDurationMs; } public static Bitmap getCachedBitmap(String url) { if (url == null) return null; Bitmap ret = null; if (mDeadCache != null) ret = mDeadCache.get(url); if (ret != null) return ret; if (mLiveCache != null) { Drawable drawable = mLiveCache.get(url); if (drawable instanceof ZombieDrawable) return ((ZombieDrawable) drawable).getBitmap(); } return null; } public static boolean isLocalFile(Context context,String url){ // if (mLiveCache.get(url) !=null) { // } String filename=getCahePath(context)+File.separator+getFilenameForUrl(url); File file = new File(filename); //HupuLog.e("papa", "------"+file.exists()); return file.exists(); } /** * Download and shrink an Image located at a specified URL, and display it * in the provided {@link ImageView}. * * @param context * A {@link Context} to allow setUrlDrawable to load and save * files. * @param imageView * The {@link ImageView} to display the image to after it is * loaded. * @param url * The URL of the image that should be loaded. * @param defaultDrawable * A {@link Drawable} that should be displayed in * {@code imageView} while the image has not been loaded. This * image will also be displayed if the image fails to load. This * can be set to {@code null}. * @param cacheDurationMs * The length of time, in milliseconds, that this image should be * cached locally. * @param callback * An instance of {@link UrlImageViewCallback} that is called * when the image successfully finishes loading. This value can * be null. */ private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, final Drawable defaultDrawable, final long cacheDurationMs, final UrlImageViewCallback callback) { assert (Looper.getMainLooper().getThread() == Thread.currentThread()) : "setUrlDrawable and loadUrlDrawable should only be called from the main thread."; cleanup(context); // disassociate this ImageView from any pending downloads if (isNullOrEmpty(url)) { if (imageView != null) { mPendingViews.remove(imageView); imageView.setImageDrawable(defaultDrawable); } return; } final int tw; final int th; if (mMetrics == null) prepareResources(context); tw = mMetrics.widthPixels; th = mMetrics.heightPixels; // Log.d("setUrlDrawable", "url=" + url); // final String filename = context.getFileStreamPath( // getFilenameForUrl(url)).getAbsolutePath(); final String filename=getCahePath(context)+File.separator+getFilenameForUrl(url); // Log.d("setUrlDrawable", "cache=" + getCahePath(context)); final File file = new File(filename); // Log.d("setUrlDrawable", "filename=" + filename+" ;exit="+file.exists()); // check the dead and live cache to see if we can find this url's bitmap if (mDeadCache == null) { mDeadCache = new LruBitmapCache(getHeapSize(context) / 8); } Drawable drawable = null; Bitmap bitmap = mDeadCache.remove(url); if (bitmap != null) { clog("zombie load: " + url); } else { drawable = mLiveCache.get(url); } // if something was found, verify it was fresh. if (drawable != null || bitmap != null) { clog("Cache hit on: " + url); // if the file age is older than the cache duration, force a // refresh. // note that the file must exist, otherwise it is using a default. // not checking for file existence would do a network call on every // 404 or failed load. if (file.exists() && !checkCacheDuration(file, cacheDurationMs)) { clog("Cache hit, but file is stale. Forcing reload: " + url); if (drawable != null && drawable instanceof ZombieDrawable) ((ZombieDrawable) drawable).headshot(); drawable = null; bitmap = null; } else { clog("Using cached: " + url); } } // if the bitmap is fresh, set the imageview if (drawable != null || bitmap != null) { if (imageView != null) { mPendingViews.remove(imageView); if (drawable instanceof ZombieDrawable) drawable = ((ZombieDrawable) drawable).clone(mResources); else if (bitmap != null) drawable = new ZombieDrawable(url, mResources, bitmap); imageView.setImageDrawable(drawable); } // invoke any bitmap callbacks if (callback != null) { // when invoking the callback from cache, check to see if this // was // a drawable that was successfully loaded from the filesystem // or url. // this will be indicated by it being a ZombieDrawable (ie, // something we are managing). // The default drawables will be BitmapDrawables (or whatever // else the user passed in). if (bitmap == null && drawable instanceof ZombieDrawable) bitmap = ((ZombieDrawable) drawable).getBitmap(); callback.onLoaded(imageView, bitmap, url, true); } return; } // oh noes, at this point we definitely do not have the file available // in memory // let's prepare for an asynchronous load of the image. // null it while it is downloading // since listviews reuse their views, we need to // take note of which url this view is waiting for. // This may change rapidly as the list scrolls or is filtered, etc. clog("Waiting for " + url + " " + imageView); if (imageView != null) { imageView.setImageDrawable(defaultDrawable); mPendingViews.put(imageView, url); } final ArrayList<ImageView> currentDownload = mPendingDownloads.get(url); if (currentDownload != null && currentDownload.size() != 0) { // Also, multiple vies may be waiting for this url. // So, let's maintain a list of these views. // When the url is downloaded, it sets the imagedrawable for // every view in the list. It needs to also validate that // the imageview is still waiting for this url. if (imageView != null) { currentDownload.add(imageView); } return; } final ArrayList<ImageView> downloads = new ArrayList<ImageView>(); if (imageView != null) { downloads.add(imageView); } mPendingDownloads.put(url, downloads); final int targetWidth = tw <= 0 ? Integer.MAX_VALUE : tw; final int targetHeight = th <= 0 ? Integer.MAX_VALUE : th; final Loader loader = new Loader() { @Override public void onDownloadComplete(UrlDownloader downloader, InputStream in, String existingFilename) { try { assert (in == null || existingFilename == null); if (in == null && existingFilename == null) return; String targetFilename = filename; if (in != null) { in = new BufferedInputStream(in, 8192); OutputStream fout = new BufferedOutputStream( new FileOutputStream(filename), 8192); copyStream(in, fout); fout.close(); } else { targetFilename = existingFilename; } result = loadBitmapFromStream(context, url, targetFilename, targetWidth, targetHeight); } catch (final Exception ex) { // always delete busted files when we throw. new File(filename).delete(); if (Constants.LOG_ENABLED) Log.e(Constants.LOGTAG, "Error loading " + url, ex); } finally { // if we're not supposed to cache this thing, delete the // temp file. if (downloader != null && !downloader.allowCache()) new File(filename).delete(); } } }; final Runnable completion = new Runnable() { @Override public void run() { assert (Looper.myLooper().equals(Looper.getMainLooper())); Bitmap bitmap = loader.result; Drawable usableResult = null; if (bitmap != null) { usableResult = new ZombieDrawable(url, mResources, bitmap); } if (usableResult == null) { clog("No usable result, defaulting " + url); usableResult = defaultDrawable; mLiveCache.put(url, usableResult); } mPendingDownloads.remove(url); // mLiveCache.put(url, usableResult); if (callback != null && imageView == null) callback.onLoaded(null, loader.result, url, false); int waitingCount = 0; for (final ImageView iv : downloads) { // validate the url it is waiting for final String pendingUrl = mPendingViews.get(iv); if (!url.equals(pendingUrl)) { clog("Ignoring out of date request to update view for " + url + " " + pendingUrl + " " + iv); continue; } waitingCount++; mPendingViews.remove(iv); if (usableResult != null) { // System.out.println(String.format("imageView: %dx%d, %dx%d", // imageView.getMeasuredWidth(), // imageView.getMeasuredHeight(), imageView.getWidth(), // imageView.getHeight())); iv.setImageDrawable(usableResult); // System.out.println(String.format("imageView: %dx%d, %dx%d", // imageView.getMeasuredWidth(), // imageView.getMeasuredHeight(), imageView.getWidth(), // imageView.getHeight())); // onLoaded is called with the loader's result (not what // is actually used). null indicates failure. } if (callback != null && iv == imageView) callback.onLoaded(iv, loader.result, url, false); } clog("Populated: " + waitingCount); } }; if (file.exists()) { try { if (checkCacheDuration(file, cacheDurationMs)) { clog("File Cache hit on: " + url + ". " + (System.currentTimeMillis() - file.lastModified()) + "ms old."); // Log.d("setUrlDrawable", "load from file=" + url); final AsyncTask<Void, Void, Void> fileloader = new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(final Void... params) { loader.onDownloadComplete(null, null, filename); return null; } @Override protected void onPostExecute(final Void result) { completion.run(); } }; executeTask(fileloader); return; } else { clog("File cache has expired. Refreshing."); } } catch (final Exception ex) { } } for (UrlDownloader downloader : mDownloaders) { if (downloader.canDownloadUrl(url)) { Log.d("setUrlDrawable", "load from web=" + url); downloader.download(context, url, filename, loader, completion); return; } } imageView.setImageDrawable(defaultDrawable); } private static abstract class Loader implements UrlDownloader.UrlDownloaderCallback { Bitmap result; } private static HttpUrlDownloader mHttpDownloader = new HttpUrlDownloader(); private static ContentUrlDownloader mContentDownloader = new ContentUrlDownloader(); private static ContactContentUrlDownloader mContactDownloader = new ContactContentUrlDownloader(); private static AssetUrlDownloader mAssetDownloader = new AssetUrlDownloader(); private static FileUrlDownloader mFileDownloader = new FileUrlDownloader(); private static ArrayList<UrlDownloader> mDownloaders = new ArrayList<UrlDownloader>(); public static ArrayList<UrlDownloader> getDownloaders() { return mDownloaders; } static { mDownloaders.add(mHttpDownloader); mDownloaders.add(mContactDownloader); mDownloaders.add(mContentDownloader); mDownloaders.add(mAssetDownloader); mDownloaders.add(mFileDownloader); } public static interface RequestPropertiesCallback { public ArrayList<NameValuePair> getHeadersForRequest(Context context, String url); } private static RequestPropertiesCallback mRequestPropertiesCallback; public static RequestPropertiesCallback getRequestPropertiesCallback() { return mRequestPropertiesCallback; } public static void setRequestPropertiesCallback( final RequestPropertiesCallback callback) { mRequestPropertiesCallback = callback; } private static DrawableCache mLiveCache = DrawableCache.getInstance(); private static LruBitmapCache mDeadCache; private static HashSet<Bitmap> mAllCache = new HashSet<Bitmap>(); @SuppressLint("NewApi") private static int getHeapSize(final Context context) { return ((ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() * 1024 * 1024; } /*** * Remove a url from the cache * * @param url * @return The bitmap removed, if any. */ public static Bitmap remove(Context context,String url) { final String filename=getCahePath(context)+File.separator+getFilenameForUrl(url); new File(filename).delete(); // new File(getFilenameForUrl(url)).delete(); Drawable drawable = mLiveCache.remove(url); if (drawable instanceof ZombieDrawable) { ZombieDrawable zombie = (ZombieDrawable) drawable; Bitmap ret = zombie.getBitmap(); zombie.headshot(); return ret; } return null; } /*** * ZombieDrawable refcounts Bitmaps by hooking the finalizer. * */ private static class ZombieDrawable extends BitmapDrawable { private static class Brains { int mRefCounter; boolean mHeadshot; } public ZombieDrawable(final String url, Resources resources, final Bitmap bitmap) { this(url, resources, bitmap, new Brains()); } Brains mBrains; private ZombieDrawable(final String url, Resources resources, final Bitmap bitmap, Brains brains) { super(resources, bitmap); mUrl = url; mBrains = brains; mAllCache.add(bitmap); mDeadCache.remove(url); mLiveCache.put(url, this); mBrains.mRefCounter++; } public ZombieDrawable clone(Resources resources) { return new ZombieDrawable(mUrl, resources, getBitmap(), mBrains); } String mUrl; @Override protected void finalize() throws Throwable { super.finalize(); mBrains.mRefCounter--; if (mBrains.mRefCounter == 0) { if (!mBrains.mHeadshot) mDeadCache.put(mUrl, getBitmap()); mAllCache.remove(getBitmap()); mLiveCache.remove(mUrl); clog("Zombie GC event " + mUrl); } } // kill this zombie, forever. public void headshot() { clog("BOOM! Headshot: " + mUrl); mBrains.mHeadshot = true; mLiveCache.remove(mUrl); mAllCache.remove(getBitmap()); } } static void executeTask(final AsyncTask<Void, Void, Void> task) { if (Build.VERSION.SDK_INT < Constants.HONEYCOMB) { task.execute(); } else { executeTaskHoneycomb(task); } } @TargetApi(Constants.HONEYCOMB) private static void executeTaskHoneycomb( final AsyncTask<Void, Void, Void> task) { task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } public static int getPendingDownloads() { return mPendingDownloads.size(); } private static Hashtable<ImageView, String> mPendingViews = new Hashtable<ImageView, String>(); private static Hashtable<String, ArrayList<ImageView>> mPendingDownloads = new Hashtable<String, ArrayList<ImageView>>(); private static String cache_path; public static final String getCahePath(Context ctx) { if (cache_path == null) { cache_path = Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) ? getExternalCacheDir(ctx) .getPath() : ctx.getCacheDir().getPath(); } return cache_path; } /** * 获取程序外部的缓存目录 * * @param context * @return */ public static File getExternalCacheDir(Context context) { final String cacheDir = "hupu/games/cache"; // Log.d("getExternalCacheDir",context.getCacheDir().getPath()); File ff =new File(Environment.getExternalStorageDirectory().getPath()+File.separator+cacheDir); if(!ff.exists()) ff.mkdirs(); // Log.d("getExternalCacheDir","file = "+ff.getAbsolutePath() +" ;exit="+ff.exists()); return ff; } /** * 获取外置SD卡路径 * * @return */ public static String getSDCardPath() { String cmd = "cat /proc/mounts"; Runtime run = Runtime.getRuntime();// 返回与当前 Java 应用程序相关的运行时对象 try { Process p = run.exec(cmd);// 启动另一个进程来执行命令 BufferedInputStream in = new BufferedInputStream(p.getInputStream()); BufferedReader inBr = new BufferedReader(new InputStreamReader(in)); String lineStr; while ((lineStr = inBr.readLine()) != null) { // 获得命令执行后在控制台的输出信息 Log.i("CommonUtil:getSDCardPath", lineStr); if (lineStr.contains("sdcard") && lineStr.contains(".android_secure")) { String[] strArray = lineStr.split(" "); if (strArray != null && strArray.length >= 5) { String result = strArray[1].replace("/.android_secure", ""); return result; } } // 检查命令是否执行失败。 if (p.waitFor() != 0 && p.exitValue() == 1) { // p.exitValue()==0表示正常结束,1:非正常结束 Log.e("CommonUtil:getSDCardPath", "命令执行失败!"); } } inBr.close(); in.close(); } catch (Exception e) { Log.e("CommonUtil:getSDCardPath", e.toString()); return Environment.getExternalStorageDirectory().getPath(); } return Environment.getExternalStorageDirectory().getPath(); } }