package fast.rocket.cache;
import fast.rocket.builder.RocketImageBuilder;
import fast.rocket.cache.ImageLoader.ImageContainer;
import fast.rocket.cache.ImageLoader.ImageListener;
import fast.rocket.error.RocketError;
import fast.rocket.utils.RocketUtils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
/**
* Handles fetching an image from a URL as well as the life-cycle of the
* associated request. Also images can be circular by adding the attributes
* in the XML resource file.
*/
public class NetworkCacheView extends ImageView {
/** Local copy of the ImageLoader. */
private ImageLoader mImageLoader;
/** Current ImageContainer. (either in-flight or finished) */
private ImageContainer mImageContainer;
/** Image cache configure builder*/
private RocketImageBuilder.Builder builder;
/**
* Instantiates a new circular cache view.
*
* @param paramContext
* the param context
*/
public NetworkCacheView(Context context) {
super(context);
}
/**
* Instantiates a new circular cache view.
*
* @param paramContext
* the param context
* @param paramAttributeSet
* the param attribute set
*/
public NetworkCacheView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Instantiates a new circular cache view.
*
* @param paramContext
* the param context
* @param paramAttributeSet
* the param attribute set
* @param paramInt
* the param int
*/
public NetworkCacheView(Context context, AttributeSet attrs, int paramInt) {
super(context, attrs, paramInt);
}
/*
* (non-Javadoc)
*
* @see android.widget.ImageView#onDraw(android.graphics.Canvas)
*/
public void onDraw(Canvas paramCanvas) {
if (RocketUtils.hasHoneycomb()) {
super.onDraw(paramCanvas);
} else {
BitmapDrawable drawable = (BitmapDrawable) getDrawable();
if (drawable == null) {
if (builder.placeholderResource != 0) {
setImageResource(builder.placeholderResource);
} else {
setImageDrawable(builder.placeholderDrawable);
}
} else if ((drawable.getBitmap() == null)
|| (drawable.getBitmap().isRecycled())) {
if (builder.placeholderResource != 0) {
setImageResource(builder.placeholderResource);
} else {
setImageDrawable(builder.placeholderDrawable);
}
}
try {
super.onDraw(paramCanvas);
} catch (RuntimeException localRuntimeException) {
}
}
}
/**
* Sets URL of the image that should be loaded into this view. Note that
* calling this will immediately either set the cached image (if available)
* or the default image specified by
*
* @param url
* The URL that should be loaded into this ImageView.
* @param imageLoader
* ImageLoader that will be used to make the request.
* @param maxWidth
* the max width
* @param maxHeight
* the max height
* @param skipDiskCache
* the skip disk cache
* @param callback
* the callback
* @param config
* the config {@link NetworkCacheView#setDefaultImageResId(int)}
* on the view.
*
* NOTE: If applicable,
* {@link NetworkCacheView#setDefaultImageResId(int)} and
* {@link NetworkCacheView#setErrorImageResId(int)} should be
* called prior to calling this function.
*/
public void setImageUrl(ImageLoader imageLoader, RocketImageBuilder.Builder builder) {
this.builder = builder;
this.mImageLoader = imageLoader;
// The URL has potentially changed. See if we need to load it.
loadImageIfNecessary(false);
}
/**
* Loads the image for the view if it isn't already loaded.
*
* @param isInLayoutPass
* True if this was invoked from a layout pass, false otherwise.
*/
private void loadImageIfNecessary(final boolean isInLayoutPass) {
if(builder == null) {
return;
}
int width = getWidth();
int height = getHeight();
boolean isFullyWrapContent = getLayoutParams() != null
&& getLayoutParams().height == LayoutParams.WRAP_CONTENT
&& getLayoutParams().width == LayoutParams.WRAP_CONTENT;
// if the view's bounds aren't known yet, and this is not a
// wrap-content/wrap-content
// view, hold off on loading the image.
if (width == 0 && height == 0 && !isFullyWrapContent) {
return;
}
// if the URL to be loaded in this view is empty, cancel any old
// requests and clear the
// currently loaded image.
if (TextUtils.isEmpty(builder.uri)) {
if (mImageContainer != null) {
mImageContainer.cancelRequest();
mImageContainer = null;
}
setDefaultImageOrNull();
return;
}
// if there was an old request in this view, check if it needs to be
// canceled.
if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
if (mImageContainer.getRequestUrl().equals(builder.uri)) {
// if the request is from the same URL, return.
return;
} else {
// if there is a pre-existing request, cancel it if it's
// fetching a different URL.
mImageContainer.cancelRequest();
setDefaultImageOrNull();
}
}
// The pre-existing content of this view didn't match the current URL.
// Load the new image
// from the network.
ImageContainer newContainer = mImageLoader.get(
new ImageListener() {
@Override
public void onErrorResponse(RocketError error) {
if (builder.errorResource != 0) {
setImageResource(builder.errorResource);
} else {
setImageDrawable(builder.errorDrawable);
}
}
@Override
public void onResponse(final ImageContainer response,
boolean isImmediate) {
// If this was an immediate response that was delivered
// inside of a layout
// pass do not set the image immediately as it will
// trigger a requestLayout
// inside of a layout. Instead, defer setting the image
// by posting back to
// the main thread.
if (isImmediate && isInLayoutPass) {
post(new Runnable() {
@Override
public void run() {
onResponse(response, false);
}
});
return;
}
if (response.getBitmap() != null) {
if(builder.listener != null) {
builder.listener.onComplete();
}
setImageBitmap(response.getBitmap());
RocketUtils.loadAnimation(
NetworkCacheView.this,
builder.inAnimation,
builder.inAnimationResource);
if(builder.callback != null) {
builder.callback.onComplete(
NetworkCacheView.this,
response.getBitmap());
}
} else {
if (builder.placeholderResource != 0) {
setImageResource(builder.placeholderResource);
} else {
setImageDrawable(builder.placeholderDrawable);
}
if(builder.callback != null) {
builder.callback.onComplete(NetworkCacheView.this, null);
}
}
}
}, builder);
// update the ImageContainer to be the new bitmap container.
mImageContainer = newContainer;
}
private void setDefaultImageOrNull() {
if (builder.placeholderResource != 0) {
setImageResource(builder.placeholderResource);
} else if (builder.placeholderDrawable != null) {
setImageDrawable(builder.placeholderDrawable);
} else {
setImageBitmap(null);
}
}
/*
* (non-Javadoc)
*
* @see android.view.View#onLayout(boolean, int, int, int, int)
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
loadImageIfNecessary(true);
}
@Override
protected void onDetachedFromWindow() {
if (mImageContainer != null) {
// If the view was bound to an image request, cancel it and clear
// out the image from the view.
mImageContainer.cancelRequest();
setImageBitmap(null);
// also clear out the container so we can reload the image if necessary.
mImageContainer = null;
}
super.onDetachedFromWindow();
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
}