Android Open Source - GreenDroid Async Image View






From Project

Back to project page GreenDroid.

License

The source code is released under:

Apache License

If you think the Android project GreenDroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
 */*from  w  w  w.j  a v a  2  s .co m*/
 * 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 greendroid.widget;

import greendroid.image.ImageProcessor;
import greendroid.image.ImageRequest;
import greendroid.image.ImageRequest.ImageRequestCallback;
import greendroid.util.Config;
import greendroid.util.GDUtils;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

import com.cyrilmottier.android.greendroid.R;

/**
 * <p>
 * A {@link AsyncImageView} is a network-aware ImageView. It may display images
 * from the web according to a URL. {@link AsyncImageView} takes care of loading
 * asynchronously images on the Internet. It also caches images in an
 * application-wide cache to prevent loading images several times.
 * </p>
 * <p>
 * Clients may listen the {@link OnImageViewLoadListener} to be notified of the
 * current image loading state.
 * </p>
 * <p>
 * {@link AsyncImageView} may be extremely useful in ListView's row. To prevent
 * your {@link AsyncImageView} from downloading while scrolling or flinging it
 * is a good idea to pause it using {@link #setPaused(boolean)} method. Once the
 * scrolling/flinging is over, <em>un-pause</em> your {@link AsyncImageView}s
 * using <code>setPaused(false)</code>
 * </p>
 * 
 * @author Cyril Mottier
 */
public class AsyncImageView extends ImageView implements ImageRequestCallback {

    private static final String LOG_TAG = AsyncImageView.class.getSimpleName();

    /**
     * Clients may listen to {@link AsyncImageView} changes using a
     * {@link OnImageViewLoadListener}.
     * 
     * @author Cyril Mottier
     */
    public static interface OnImageViewLoadListener {

        /**
         * Called when the image started to load
         * 
         * @param imageView The AsyncImageView that started loading
         */
        void onLoadingStarted(AsyncImageView imageView);

        /**
         * Called when the image ended to load that is when the image has been
         * downloaded and is ready to be displayed on screen
         * 
         * @param imageView The AsyncImageView that ended loading
         */
        void onLoadingEnded(AsyncImageView imageView, Bitmap image);

        /**
         * Called when the image loading failed
         * 
         * @param imageView The AsyncImageView that failed to load
         */
        void onLoadingFailed(AsyncImageView imageView, Throwable throwable);
    }

    private static final int IMAGE_SOURCE_UNKNOWN = -1;
    private static final int IMAGE_SOURCE_RESOURCE = 0;
    private static final int IMAGE_SOURCE_DRAWABLE = 1;
    private static final int IMAGE_SOURCE_BITMAP = 2;

    private int mImageSource;
    private Bitmap mDefaultBitmap;
    private Drawable mDefaultDrawable;
    private int mDefaultResId;

    private String mUrl;
    private ImageRequest mRequest;
    private boolean mPaused;

    private Bitmap mBitmap;
    private OnImageViewLoadListener mOnImageViewLoadListener;
    private ImageProcessor mImageProcessor;
    private BitmapFactory.Options mOptions;

    public AsyncImageView(Context context) {
        this(context, null);
    }

    public AsyncImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        initializeDefaultValues();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AsyncImageView, defStyle, 0);

        Drawable d = a.getDrawable(R.styleable.AsyncImageView_defaultSrc);
        if (d != null) {
            setDefaultImageDrawable(d);
        }

        final int inDensity = a.getInt(R.styleable.AsyncImageView_inDensity, -1);
        if (inDensity != -1) {
            setInDensity(inDensity);
        }

        setUrl(a.getString(R.styleable.AsyncImageView_url));

        a.recycle();
    }

    private void initializeDefaultValues() {
        mImageSource = IMAGE_SOURCE_UNKNOWN;
        mPaused = false;
    }

    /**
     * Return true if this AsyncImageView is currently loading an image.
     * 
     * @return true if this AsyncImageView is currently loading an image.
     *         Otherwise it returns false.
     */
    public boolean isLoading() {
        return mRequest != null;
    }

    /**
     * Return true if the displayed image has been correctly loaded.
     * 
     * @return true if this AsyncImageView succeed to load the image at the
     *         given url.
     */
    public boolean isLoaded() {
        return mRequest == null && mBitmap != null;
    }

    /**
     * Pause this AsyncImageView preventing it from downloading the image. The
     * download process will start back once setPaused(false) is called.
     * 
     * @param paused
     */
    public void setPaused(boolean paused) {
        if (mPaused != paused) {
            mPaused = paused;
            if (!paused) {
                reload();
            }
        }
    }

    /**
     * Helper to {@link #setOptions(Options)} that simply sets the inDensity for
     * loaded image.
     * 
     * @param inDensity
     * @see AsyncImageView#setOptions(Options)
     */
    public void setInDensity(int inDensity) {
        if (mOptions == null) {
            mOptions = new BitmapFactory.Options();
            mOptions.inDither = true;
            mOptions.inScaled = true;
            mOptions.inTargetDensity = getContext().getResources().getDisplayMetrics().densityDpi;
        }

        mOptions.inDensity = inDensity;
    }

    /**
     * Assign an Options object to this {@link AsyncImageView}. Those options
     * are used internally by the {@link AsyncImageView} when decoding the
     * image. This may be used to prevent the default behavior that loads all
     * images as mdpi density.
     * 
     * @param options
     */
    public void setOptions(BitmapFactory.Options options) {
        mOptions = options;
    }

    /**
     * Reload the image pointed by the given URL
     */
    public void reload() {
        reload(false);
    }

    /**
     * Reload the image pointed by the given URL. You may want to force
     * reloading by setting the force parameter to true.
     * 
     * @param force if true the AsyncImageView won't look into the
     *            application-wide cache.
     */
    public void reload(boolean force) {
        if (mRequest == null && mUrl != null) {

            // Prior downloading the image ... let's look in a cache !
            // TODO cyril: This is a synchronous call ... make it asynchronous
            mBitmap = null;
            if (!force) {
                mBitmap = GDUtils.getImageCache(getContext()).get(mUrl);
            }

            if (mBitmap != null) {
                setImageBitmap(mBitmap);
                return;
            }

            if (Config.GD_INFO_LOGS_ENABLED) {
                Log.i(LOG_TAG, "Cache miss. Starting to load the image at the given URL");
            }

            setDefaultImage();
            mRequest = new ImageRequest(mUrl, this, mImageProcessor, mOptions);
            mRequest.load(getContext());
        }
    }

    /**
     * Force the loading to be stopped.
     */
    public void stopLoading() {
        if (mRequest != null) {
            mRequest.cancel();
            mRequest = null;
        }
    }

    /**
     * Register a callback to be invoked when an event occured for this
     * AsyncImageView.
     * 
     * @param listener The listener that will be notified
     */
    public void setOnImageViewLoadListener(OnImageViewLoadListener listener) {
        mOnImageViewLoadListener = listener;
    }

    /**
     * Set the url of the image that will be used as the content of this
     * AsyncImageView. The given may be null in order to display the default
     * image. Please note the url may be a local url. For instance, you can
     * asynchronously load images from the disk memory is the url scheme is
     * <code>file://</code>
     * 
     * @param url The url of the image to set. Pass null to force the
     *            AsyncImageView to display the default image
     */
    public void setUrl(String url) {

        // Check the url has changed
        if (mBitmap != null && url != null && url.equals(mUrl)) {
            return;
        }

        stopLoading();
        mUrl = url;

        // Setting the url to an empty string force the displayed image to the
        // default image
        if (TextUtils.isEmpty(mUrl)) {
            mBitmap = null;
            setDefaultImage();
        } else {
            if (!mPaused) {
                reload();
            } else {
                // We're paused: let's look in a synchronous and efficient cache
                // prior using the default image.
                mBitmap = GDUtils.getImageCache(getContext()).get(mUrl);
                if (mBitmap != null) {
                    setImageBitmap(mBitmap);
                    return;
                } else {
                    setDefaultImage();
                }
            }
        }
    }

    /**
     * Set the default bitmap as the content of this AsyncImageView
     * 
     * @param bitmap The bitmap to set
     */
    public void setDefaultImageBitmap(Bitmap bitmap) {
        mImageSource = IMAGE_SOURCE_BITMAP;
        mDefaultBitmap = bitmap;
        setDefaultImage();
    }

    /**
     * Set the default drawable as the content of this AsyncImageView
     * 
     * @param drawable The drawable to set
     */
    public void setDefaultImageDrawable(Drawable drawable) {
        mImageSource = IMAGE_SOURCE_DRAWABLE;
        mDefaultDrawable = drawable;
        setDefaultImage();
    }

    /**
     * Set the default resource as the content of this AsyncImageView
     * 
     * @param resId The resource identifier to set
     */
    public void setDefaultImageResource(int resId) {
        mImageSource = IMAGE_SOURCE_RESOURCE;
        mDefaultResId = resId;
        setDefaultImage();
    }

    /**
     * Set an image processor to this AsyncImageView. An ImageProcessor may be
     * used in order to work on the retrieved Bitmap prior displaying it on
     * screen.
     * 
     * @param imageProcessor The {@link ImageProcessor} to set
     * @see ImageProcessor
     */
    public void setImageProcessor(ImageProcessor imageProcessor) {
        mImageProcessor = imageProcessor;
    }

    private void setDefaultImage() {
        if (mBitmap == null) {
            switch (mImageSource) {
                case IMAGE_SOURCE_BITMAP:
                    setImageBitmap(mDefaultBitmap);
                    break;
                case IMAGE_SOURCE_DRAWABLE:
                    setImageDrawable(mDefaultDrawable);
                    break;
                case IMAGE_SOURCE_RESOURCE:
                    setImageResource(mDefaultResId);
                    break;
                default:
                    setImageDrawable(null);
                    break;
            }
        }
    }

    static class SavedState extends BaseSavedState {
        String url;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            url = in.readString();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeString(url);
        }

        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);

        ss.url = mUrl;

        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        setUrl(ss.url);
    }

    public void onImageRequestStarted(ImageRequest request) {
        if (mOnImageViewLoadListener != null) {
            mOnImageViewLoadListener.onLoadingStarted(this);
        }
    }

    public void onImageRequestFailed(ImageRequest request, Throwable throwable) {
        mRequest = null;
        if (mOnImageViewLoadListener != null) {
            mOnImageViewLoadListener.onLoadingFailed(this, throwable);
        }
    }

    public void onImageRequestEnded(ImageRequest request, Bitmap image) {
        mBitmap = image;
        setImageBitmap(image);
        if (mOnImageViewLoadListener != null) {
            mOnImageViewLoadListener.onLoadingEnded(this, image);
        }
        mRequest = null;
    }

    public void onImageRequestCancelled(ImageRequest request) {
        mRequest = null;
        if (mOnImageViewLoadListener != null) {
            mOnImageViewLoadListener.onLoadingFailed(this, null);
        }
    }
}




Java Source Code List

com.cyrilmottier.android.gdcatalog.AboutActivity.java
com.cyrilmottier.android.gdcatalog.ActionBarActivity.java
com.cyrilmottier.android.gdcatalog.AsyncImageViewListActivity.java
com.cyrilmottier.android.gdcatalog.BasicItemActivity.java
com.cyrilmottier.android.gdcatalog.CatalogActivity.java
com.cyrilmottier.android.gdcatalog.CatalogApplication.java
com.cyrilmottier.android.gdcatalog.InfoTabActivity.java
com.cyrilmottier.android.gdcatalog.MapPinMapActivity.java
com.cyrilmottier.android.gdcatalog.PagedViewActivity.java
com.cyrilmottier.android.gdcatalog.QuickActionActivity.java
com.cyrilmottier.android.gdcatalog.SegmentedActivity.java
com.cyrilmottier.android.gdcatalog.SimpleAsyncImageViewActivity.java
com.cyrilmottier.android.gdcatalog.TabbedActionBarActivity.java
com.cyrilmottier.android.gdcatalog.TweakedItemViewActivity.java
com.cyrilmottier.android.gdcatalog.WebContentActivity.java
com.cyrilmottier.android.gdcatalog.XmlItemActivity.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItemView.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItem.java
greendroid.app.ActionBarActivity.java
greendroid.app.GDActivity.java
greendroid.app.GDApplication.java
greendroid.app.GDExpandableListActivity.java
greendroid.app.GDListActivity.java
greendroid.app.GDMapActivity.java
greendroid.app.GDTabActivity.java
greendroid.graphics.drawable.ActionBarDrawable.java
greendroid.graphics.drawable.DrawableStateSet.java
greendroid.graphics.drawable.MapPinDrawable.java
greendroid.image.ChainImageProcessor.java
greendroid.image.ImageCache.java
greendroid.image.ImageLoader.java
greendroid.image.ImageProcessor.java
greendroid.image.ImageRequest.java
greendroid.image.MaskImageProcessor.java
greendroid.image.ScaleImageProcessor.java
greendroid.util.Config.java
greendroid.util.GDUtils.java
greendroid.util.Md5Util.java
greendroid.util.Time.java
greendroid.widget.ActionBarHost.java
greendroid.widget.ActionBarItem.java
greendroid.widget.ActionBar.java
greendroid.widget.AsyncImageView.java
greendroid.widget.ItemAdapter.java
greendroid.widget.LoaderActionBarItem.java
greendroid.widget.NormalActionBarItem.java
greendroid.widget.PageIndicator.java
greendroid.widget.PagedAdapter.java
greendroid.widget.PagedView.java
greendroid.widget.QuickActionBar.java
greendroid.widget.QuickActionGrid.java
greendroid.widget.QuickActionWidget.java
greendroid.widget.QuickAction.java
greendroid.widget.SegmentedAdapter.java
greendroid.widget.SegmentedBar.java
greendroid.widget.SegmentedHost.java
greendroid.widget.item.DescriptionItem.java
greendroid.widget.item.DrawableItem.java
greendroid.widget.item.Item.java
greendroid.widget.item.LongTextItem.java
greendroid.widget.item.ProgressItem.java
greendroid.widget.item.SeparatorItem.java
greendroid.widget.item.SubtextItem.java
greendroid.widget.item.SubtitleItem.java
greendroid.widget.item.TextItem.java
greendroid.widget.item.ThumbnailItem.java
greendroid.widget.itemview.DescriptionItemView.java
greendroid.widget.itemview.DrawableItemView.java
greendroid.widget.itemview.ItemView.java
greendroid.widget.itemview.LongTextItemView.java
greendroid.widget.itemview.ProgressItemView.java
greendroid.widget.itemview.SeparatorItemView.java
greendroid.widget.itemview.SubtextItemView.java
greendroid.widget.itemview.SubtitleItemView.java
greendroid.widget.itemview.TextItemView.java
greendroid.widget.itemview.ThumbnailItemView.java