Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
21478 rajender 1
/**
2
 * Copyright (C) 2013 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.android.volley.toolbox;
17
 
18
import android.content.Context;
19
import android.text.TextUtils;
20
import android.util.AttributeSet;
21
import android.view.ViewGroup.LayoutParams;
22
import android.widget.ImageView;
23
 
24
import com.android.volley.VolleyError;
25
import com.android.volley.toolbox.ImageLoader.ImageContainer;
26
import com.android.volley.toolbox.ImageLoader.ImageListener;
27
 
28
/**
29
 * Handles fetching an image from a URL as well as the life-cycle of the
30
 * associated request.
31
 */
32
public class NetworkImageView extends ImageView {
33
    /** The URL of the network image to load */
34
    private String mUrl;
35
 
36
    /**
37
     * Resource ID of the image to be used as a placeholder until the network image is loaded.
38
     */
39
    private int mDefaultImageId;
40
 
41
    /**
42
     * Resource ID of the image to be used if the network response fails.
43
     */
44
    private int mErrorImageId;
45
 
46
    /** Local copy of the ImageLoader. */
47
    private ImageLoader mImageLoader;
48
 
49
    /** Current ImageContainer. (either in-flight or finished) */
50
    private ImageContainer mImageContainer;
51
 
52
    public NetworkImageView(Context context) {
53
        this(context, null);
54
    }
55
 
56
    public NetworkImageView(Context context, AttributeSet attrs) {
57
        this(context, attrs, 0);
58
    }
59
 
60
    public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {
61
        super(context, attrs, defStyle);
62
    }
63
 
64
    /**
65
     * Sets URL of the image that should be loaded into this view. Note that calling this will
66
     * immediately either set the cached image (if available) or the default image specified by
67
     * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
68
     *
69
     * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and
70
     * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling
71
     * this function.
72
     *
73
     * @param url The URL that should be loaded into this ImageView.
74
     * @param imageLoader ImageLoader that will be used to make the request.
75
     */
76
    public void setImageUrl(String url, ImageLoader imageLoader) {
77
        mUrl = url;
78
        mImageLoader = imageLoader;
79
        // The URL has potentially changed. See if we need to load it.
80
        loadImageIfNecessary(false);
81
    }
82
 
83
    /**
84
     * Sets the default image resource ID to be used for this view until the attempt to load it
85
     * completes.
86
     */
87
    public void setDefaultImageResId(int defaultImage) {
88
        mDefaultImageId = defaultImage;
89
    }
90
 
91
    /**
92
     * Sets the error image resource ID to be used for this view in the event that the image
93
     * requested fails to load.
94
     */
95
    public void setErrorImageResId(int errorImage) {
96
        mErrorImageId = errorImage;
97
    }
98
 
99
    /**
100
     * Loads the image for the view if it isn't already loaded.
101
     * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
102
     */
103
    void loadImageIfNecessary(final boolean isInLayoutPass) {
104
        int width = getWidth();
105
        int height = getHeight();
106
        ScaleType scaleType = getScaleType();
107
 
108
        boolean wrapWidth = false, wrapHeight = false;
109
        if (getLayoutParams() != null) {
110
            wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
111
            wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;
112
        }
113
 
114
        // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
115
        // view, hold off on loading the image.
116
        boolean isFullyWrapContent = wrapWidth && wrapHeight;
117
        if (width == 0 && height == 0 && !isFullyWrapContent) {
118
            return;
119
        }
120
 
121
        // if the URL to be loaded in this view is empty, cancel any old requests and clear the
122
        // currently loaded image.
123
        if (TextUtils.isEmpty(mUrl)) {
124
            if (mImageContainer != null) {
125
                mImageContainer.cancelRequest();
126
                mImageContainer = null;
127
            }
128
            setDefaultImageOrNull();
129
            return;
130
        }
131
 
132
        // if there was an old request in this view, check if it needs to be canceled.
133
        if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
134
            if (mImageContainer.getRequestUrl().equals(mUrl)) {
135
                // if the request is from the same URL, return.
136
                return;
137
            } else {
138
                // if there is a pre-existing request, cancel it if it's fetching a different URL.
139
                mImageContainer.cancelRequest();
140
                setDefaultImageOrNull();
141
            }
142
        }
143
 
144
        // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
145
        int maxWidth = wrapWidth ? 0 : width;
146
        int maxHeight = wrapHeight ? 0 : height;
147
 
148
        // The pre-existing content of this view didn't match the current URL. Load the new image
149
        // from the network.
150
        ImageContainer newContainer = mImageLoader.get(mUrl,
151
                new ImageListener() {
152
                    @Override
153
                    public void onErrorResponse(VolleyError error) {
154
                        if (mErrorImageId != 0) {
155
                            setImageResource(mErrorImageId);
156
                        }
157
                    }
158
 
159
                    @Override
160
                    public void onResponse(final ImageContainer response, boolean isImmediate) {
161
                        // If this was an immediate response that was delivered inside of a layout
162
                        // pass do not set the image immediately as it will trigger a requestLayout
163
                        // inside of a layout. Instead, defer setting the image by posting back to
164
                        // the main thread.
165
                        if (isImmediate && isInLayoutPass) {
166
                            post(new Runnable() {
167
                                @Override
168
                                public void run() {
169
                                    onResponse(response, false);
170
                                }
171
                            });
172
                            return;
173
                        }
174
 
175
                        if (response.getBitmap() != null) {
176
                            setImageBitmap(response.getBitmap());
177
                        } else if (mDefaultImageId != 0) {
178
                            setImageResource(mDefaultImageId);
179
                        }
180
                    }
181
                }, maxWidth, maxHeight, scaleType);
182
 
183
        // update the ImageContainer to be the new bitmap container.
184
        mImageContainer = newContainer;
185
    }
186
 
187
    private void setDefaultImageOrNull() {
188
        if(mDefaultImageId != 0) {
189
            setImageResource(mDefaultImageId);
190
        }
191
        else {
192
            setImageBitmap(null);
193
        }
194
    }
195
 
196
    @Override
197
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
198
        super.onLayout(changed, left, top, right, bottom);
199
        loadImageIfNecessary(true);
200
    }
201
 
202
    @Override
203
    protected void onDetachedFromWindow() {
204
        if (mImageContainer != null) {
205
            // If the view was bound to an image request, cancel it and clear
206
            // out the image from the view.
207
            mImageContainer.cancelRequest();
208
            setImageBitmap(null);
209
            // also clear out the container so we can reload the image if necessary.
210
            mImageContainer = null;
211
        }
212
        super.onDetachedFromWindow();
213
    }
214
 
215
    @Override
216
    protected void drawableStateChanged() {
217
        super.drawableStateChanged();
218
        invalidate();
219
    }
220
}