PS:最后一篇关于Volley框架的博客...
学习内容:
1.使用ImageRequest.java实现网络图片加载
2.使用ImageLoader.java实现网络图片加载
3.使用NetWorkImageView.java实现网络图片加载
Volley的第三个作用就是实现网络图片的加载,图片加载在Volley中有三种不同的方式,各有各的用法,只是后两个还算是有相关联系的,因为NetWorkImageView是基于ImageLoader的..内部的图片加载还是使用ImageLoader,只是在后续的过程中有一些不同...
1.ImageRequest.java
使用ImageRequest加载图片数据,ImageRequest没有什么特殊的,也需要建立一个请求队列,向请求队列当中添加这次请求就可以完成图片数据的加载...
package com.android.volley.toolbox; import com.android.volley.DefaultRetryPolicy; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyLog; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; public class ImageRequest extends Request<Bitmap> { /** Socket timeout in milliseconds for image requests */ private static final int IMAGE_TIMEOUT_MS = 1000; //超时时间的定义.. /** Default number of retries for image requests */ private static final int IMAGE_MAX_RETRIES = 2; //一次最多重试的图片数量... /** Default backoff multiplier for image requests */ private static final float IMAGE_BACKOFF_MULT = 2f; //后退请求的数量.. private final Response.Listener<Bitmap> mListener; //成功监听.. private final Config mDecodeConfig; //属性编码... private final int mMaxWidth; //最大宽度... private final int mMaxHeight; //最大高度... /** Decoding lock so that we don‘t decode more than one image at a time (to avoid OOM‘s) */ private static final Object sDecodeLock = new Object(); //一个编码锁..目的是一次只能对一个图片进行编码,加载,避免OOM的发生... //指定url来创建一个ImageRequest请求... public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, Config decodeConfig, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); setRetryPolicy( new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT)); mListener = listener; mDecodeConfig = decodeConfig; mMaxWidth = maxWidth; mMaxHeight = maxHeight; } //获取优先级...图片加载的优先级一般是最低的.. @Override public Priority getPriority() { return Priority.LOW; } //重新设置图片的大小...其实为了缩小图片... private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary) { // If no dominant value at all, just return the actual. if (maxPrimary == 0 && maxSecondary == 0) { return actualPrimary; } // If primary is unspecified, scale primary to match secondary‘s scaling ratio. if (maxPrimary == 0) { double ratio = (double) maxSecondary / (double) actualSecondary; return (int) (actualPrimary * ratio); } if (maxSecondary == 0) { return maxPrimary; } double ratio = (double) actualSecondary / (double) actualPrimary; int resized = maxPrimary; if (resized * ratio > maxSecondary) { resized = (int) (maxSecondary / ratio); } return resized; } //解析响应... @Override protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) { // Serialize all decode on a global lock to reduce concurrent heap usage. synchronized (sDecodeLock) { try { return doParse(response); //调用doParse函数.. } catch (OutOfMemoryError e) { VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl()); return Response.error(new ParseError(e)); } } } /** * The real guts of parseNetworkResponse. Broken out for readability. */ //获取图片数据的过程... private Response<Bitmap> doParse(NetworkResponse response) { byte[] data = response.data; //图片数据... BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); //定义一个位图选项对象.. Bitmap bitmap = null; if (mMaxWidth == 0 && mMaxHeight == 0) {//这里表示如果为0,那么表示图片按照图片本身的大小进行展现..不用进行其他操作... decodeOptions.inPreferredConfig = mDecodeConfig; bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); } else { // If we have to resize this image, first get the natural bounds. decodeOptions.inJustDecodeBounds = true; //表示图片需要缩放.. BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);//这里并不是完全对图片进行编码,而是获取图片的基本参数.. int actualWidth = decodeOptions.outWidth; //获取图片的宽度... int actualHeight = decodeOptions.outHeight; //获取图片的高度.. // Then compute the dimensions we would ideally like to decode to. int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight, actualWidth, actualHeight); //对宽度进行缩放... int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth, actualHeight, actualWidth); //对高度进行缩放... // Decode to the nearest power of two scaling factor. decodeOptions.inJustDecodeBounds = false; //缩放后,表示图片不需要进行缩放了... // TODO(ficus): Do we need this or is it okay since API 8 doesn‘t support it? // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED; decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);//根据实际大小和所需大小去找到一个最合适的大小... Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);//对图片编码,转化成比特流的形式... // If necessary, scale down to the maximal acceptable size. if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) { //这里表示如果通过上述缩放后图片的大小仍然比所需大小要大,那么按照所需大小进一步进行缩放... bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true); tempBitmap.recycle(); } else { bitmap = tempBitmap; //否则直接为当前临时图片... } } if (bitmap == null) { return Response.error(new ParseError(response)); //返回错误数据.. } else { return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response)); //返回成功数据... } } //对响应分发... @Override protected void deliverResponse(Bitmap response) { mListener.onResponse(response); } //需找最优大小.. static int findBestSampleSize( int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) { double wr = (double) actualWidth / desiredWidth; double hr = (double) actualHeight / desiredHeight; double ratio = Math.min(wr, hr); float n = 1.0f; while ((n * 2) <= ratio) { n *= 2; } return (int) n; } }
源码看起来其实并不是非常的困难,还是比较好理解的..如果预先对ImageLoader加载图片非常熟悉的话,那么这个理解起来就不是非常的费劲...源码就分析到这,还是看看调用过程..这里的构造函数需要传递六个参数...
public ImageRequest(url,Listener,maxWidth,maxHeight,Config,errorListener);
传递的参数分别是url,成功监听,最大宽度和高度,图片使用的颜色属性,以及失败后的监听...这里宽度和高度如果指定成自定义的大小,那么图图片就会按照指定大小进行缩放,如果都指定成0,那么图片按照原本大小进行显示,不进行缩放设置...
package com.example.oop; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.ImageLoader.ImageCache; import com.android.volley.toolbox.NetworkImageView; import com.android.volley.toolbox.Volley; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.support.v4.util.LruCache; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity implements OnClickListener { String url="http://192.168.199.172:8080/JSP/imageview.jpg"; ImageView iv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iv=(ImageView)findViewById(R.id.iv); init(); } public void init(){ RequestQueue queue=Volley.newRequestQueue(MainActivity.this); queue.add(new ImageRequest("http://192.168.199.172:8080/JSP/imageview.jpg",new Listener<Bitmap>(){ @Override public void onResponse(Bitmap response){ //自定义了一个imageview...图片资源就是下载后的Bitmap iv.setImageBitmap(response); } },0,0,Config.ARGB_8888, new ErrorListener(){ @Override public void onErrorResponse(VolleyError error){ System.out.println(error.toString()); } })); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
这样就成功的使用ImageRequest加载了网络上的图片数据...但是使用ImageRequest加载网络图片的缺点是没有缓存机制,只能频繁的发送网络请求,而没有缓存请求,这样会增加服务器的负担...因此在这点上ImageRequest并不是非常的完善...
2.ImageLoader.java
ImageLoader算是对ImageRequest的一个强化,这个类内部提供了缓存机制,这样我们可以更好的去处理请求,由于存在缓存,那么相同的请求可以通过从缓存中直接获取相关的数据,从而能够减少一些不必要的请求,这样会减少网络请求,减少服务器的负担...
package com.android.volley.toolbox; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.os.Handler; import android.os.Looper; import android.widget.ImageView; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageRequest; import java.util.HashMap; import java.util.LinkedList; public class ImageLoader { /** RequestQueue for dispatching ImageRequests onto. */ private final RequestQueue mRequestQueue; //请求队列.. /** Amount of time to wait after first response arrives before delivering all responses. */ private int mBatchResponseDelayMs = 100; //响应到达的延时... /** The cache implementation to be used as an L1 cache before calling into volley. */ private final ImageCache mCache; //图片缓存对象... private final HashMap<String, BatchedImageRequest> mInFlightRequests = new HashMap<String, BatchedImageRequest>(); //表示正在处理的请求集合... /** HashMap of the currently pending responses (waiting to be delivered). */ private final HashMap<String, BatchedImageRequest> mBatchedResponses = new HashMap<String, BatchedImageRequest>(); //批处理响应的集合.. /** Handler to the main thread. */ private final Handler mHandler = new Handler(Looper.getMainLooper()); /** Runnable for in-flight response delivery. */ private Runnable mRunnable; //用于分发响应... //缓存对象构造... public interface ImageCache { public Bitmap getBitmap(String url); public void putBitmap(String url, Bitmap bitmap); } //通过一个请求队列和缓存机制来构造一个ImageLoader对象... public ImageLoader(RequestQueue queue, ImageCache imageCache) { mRequestQueue = queue; mCache = imageCache; } //获取图片监听... public static ImageListener getImageListener(final ImageView view, final int defaultImageResId, final int errorImageResId) { return new ImageListener() { //失败的监听... @Override public void onErrorResponse(VolleyError error) { if (errorImageResId != 0) { view.setImageResource(errorImageResId); //如果加载失败,使用默认图片来显示... } } @Override public void onResponse(ImageContainer response, boolean isImmediate) { if (response.getBitmap() != null) { view.setImageBitmap(response.getBitmap());//如果响应数据不为空,那么显示网络图片... } else if (defaultImageResId != 0) { view.setImageResource(defaultImageResId);//失败显示默认图片... } } }; } //失败监听的一个接口... public interface ImageListener extends ErrorListener { public void onResponse(ImageContainer response, boolean isImmediate); } //如果请求允许缓存,那么保存缓存数据... public boolean isCached(String requestUrl, int maxWidth, int maxHeight) { throwIfNotOnMainThread(); String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight); return mCache.getBitmap(cacheKey) != null; } //调用下面的函数... public ImageContainer get(String requestUrl, final ImageListener listener) { return get(requestUrl, listener, 0, 0); } //获取图片的过程... public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight) { // only fulfill requests that were initiated from the main thread. throwIfNotOnMainThread(); //如果缓存中存在,那么从缓存当中取出数据... final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight); Bitmap cachedBitmap = mCache.getBitmap(cacheKey); if (cachedBitmap != null) { //缓存存在... // Return the cached bitmap. ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);//将缓存数据的图片,以及url进行封装,返回... imageListener.onResponse(container, true); return container; } ImageContainer imageContainer = new ImageContainer(null, requestUrl, cacheKey, imageListener); //缓存不存在,新建立一个ImageContainer对象... // Update the caller to let them know that they should use the default bitmap. //回调函数,使用默认图片... imageListener.onResponse(imageContainer, true); // Check to see if a request is already in-flight. BatchedImageRequest request = mInFlightRequests.get(cacheKey); //查看当前执行队列中是否有与之相同的请求.. if (request != null) { // If it is, add this request to the list of listeners. request.addContainer(imageContainer); //如果有,那么加入到批处理请求队列当中,由这个请求队列去处理这些相同的请求.. return imageContainer; } //如果没有,那么新建立一个请求... Request<?> newRequest = new ImageRequest(requestUrl, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { onGetImageSuccess(cacheKey, response); } }, maxWidth, maxHeight, Config.RGB_565, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { onGetImageError(cacheKey, error); } }); //添加新请求到请求队列当中 mRequestQueue.add(newRequest); //向当前请求队列中加入这次请求的键和值... mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; } //设置批处理响应的延时... public void setBatchedResponseDelay(int newBatchedResponseDelayMs) { mBatchResponseDelayMs = newBatchedResponseDelayMs; } //成功获取图片... private void onGetImageSuccess(String cacheKey, Bitmap response) { // cache the image that was fetched. mCache.putBitmap(cacheKey, response); //向缓存中放入数据... // remove the request from the list of in-flight requests. BatchedImageRequest request = mInFlightRequests.remove(cacheKey); //请求成功,那么表示所有与之相同的请求都获取到了相关数据,那么就将请求移出队列... if (request != null) { // Update the response bitmap. request.mResponseBitmap = response; // Send the batched response batchResponse(cacheKey, request);//发送相同请求的响应... } } //获取图片失败的时候和成功时执行的操作基本是相同的... private void onGetImageError(String cacheKey, VolleyError error) { // Notify the requesters that something failed via a null result. // Remove this request from the list of in-flight requests. BatchedImageRequest request = mInFlightRequests.remove(cacheKey); // Set the error for this request request.setError(error); if (request != null) { // Send the batched response batchResponse(cacheKey, request); } } //ImageContainer类.. public class ImageContainer { private Bitmap mBitmap; //图片对象.. private final ImageListener mListener; //成功监听.. /** The cache key that was associated with the request */ private final String mCacheKey; //缓存键值 /** The request URL that was specified */ private final String mRequestUrl; //url地址... //将图片,url,缓存键值,以及监听的一个封装... public ImageContainer(Bitmap bitmap, String requestUrl, String cacheKey, ImageListener listener) { mBitmap = bitmap; mRequestUrl = requestUrl; mCacheKey = cacheKey; mListener = listener; } //是否中断了请求... public void cancelRequest() { if (mListener == null) { return; } BatchedImageRequest request = mInFlightRequests.get(mCacheKey); if (request != null) { boolean canceled = request.removeContainerAndCancelIfNecessary(this); //请求如果中断,那么判断是否有必要中断请求... if (canceled) { mInFlightRequests.remove(mCacheKey); //如果有必要,直接中断处理... } } else { // check to see if it is already batched for delivery. request = mBatchedResponses.get(mCacheKey); //判断请求的响应是否已经被分发... if (request != null) { request.removeContainerAndCancelIfNecessary(this);//判断是否有必要移除所有与之相同的请求并中断.. if (request.mContainers.size() == 0) { //如果同一种请求已经空了,那么就从批处理请求中移除这个键值.. mBatchedResponses.remove(mCacheKey); } } } } //获取图片数据... public Bitmap getBitmap() { return mBitmap; } //获取url... public String getRequestUrl() { return mRequestUrl; } } private class BatchedImageRequest { /** The request being tracked */ private final Request<?> mRequest; //请求对象.. /** The result of the request being tracked by this item */ private Bitmap mResponseBitmap; //位图对象... /** Error if one occurred for this response */ private VolleyError mError; //错误对象... private final LinkedList<ImageContainer> mContainers = new LinkedList<ImageContainer>(); //用于保存相同的键值对应的请求... //构造函数... public BatchedImageRequest(Request<?> request, ImageContainer container) { mRequest = request; mContainers.add(container); } /** * Set the error for this response */ public void setError(VolleyError error) { mError = error; } /** * Get the error for this response */ public VolleyError getError() { return mError; } //将每一个不同的请求加入队列中 public void addContainer(ImageContainer container) { mContainers.add(container); } //是否有必要中断请求... public boolean removeContainerAndCancelIfNecessary(ImageContainer container) { mContainers.remove(container); if (mContainers.size() == 0) { mRequest.cancel(); return true; } return false; } } //批处理响应... private void batchResponse(String cacheKey, BatchedImageRequest request) { mBatchedResponses.put(cacheKey, request);//放入响应... //开启一个线程分发响应的过程... if (mRunnable == null) { mRunnable = new Runnable() { @Override public void run() { for (BatchedImageRequest bir : mBatchedResponses.values()) { for (ImageContainer container : bir.mContainers) { // If one of the callers in the batched request canceled the request // after the response was received but before it was delivered, // skip them. if (container.mListener == null) { continue; } if (bir.getError() == null) { container.mBitmap = bir.mResponseBitmap; container.mListener.onResponse(container, false); } else { container.mListener.onErrorResponse(bir.getError()); } } } mBatchedResponses.clear(); mRunnable = null; } }; // Post the runnable. mHandler.postDelayed(mRunnable, mBatchResponseDelayMs); } } private void throwIfNotOnMainThread() { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("ImageLoader must be invoked from the main thread."); } } //获取缓存中的键值.. private static String getCacheKey(String url, int maxWidth, int maxHeight) { return new StringBuilder(url.length() + 12).append("#W").append(maxWidth) .append("#H").append(maxHeight).append(url).toString(); } }
这个源码相对就比较多,但是其中的过程并不是非常的难理解...还是看一下实际中是如何使用的...
package com.example.oop; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.ImageLoader.ImageCache; import com.android.volley.toolbox.NetworkImageView; import com.android.volley.toolbox.Volley; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.support.v4.util.LruCache; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity implements OnClickListener { String url="http://192.168.199.172:8080/JSP/imageview.jpg"; ImageView iv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView=(ImageView) findViewById(R.id.iv); init(); } public void init(){ RequestQueue queue=Volley.newRequestQueue(MainActivity.this); ImageLoader imageLoader=new ImageLoader(queue, new ImageCache() { LruCache<String,Bitmap>cache=new LruCache<String, Bitmap>(((int) Runtime.getRuntime().maxMemory())/8){ @Override protected int sizeOf(String key,Bitmap bitmap){ return bitmap.getRowBytes()*bitmap.getHeight(); } }; @Override public void putBitmap(String url, Bitmap bitmap) { // TODO Auto-generated method stub cache.put(url, bitmap); } @Override public Bitmap getBitmap(String url) { // TODO Auto-generated method stub return cache.get(url); } }); //为ImageLoader设置监听...成功则iv显示成功图片,没加载完显示默认图片,加载失败显示失败图片.. ImageListener imagelistener=imageLoader.getImageListener(iv,default_image,error_image);
imageloader.get(url,imagelistener); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
imageloader.get(url,imagelistener);获取图片的最终过程...这里get函数首先判断图片是否有缓存,通过url的形式来判断是否存在缓存,缓存内部存在,那么直接从缓存中取出,如果缓存中不存在,那么首先看本次的请求是否在批处理图像请求队列中,如果队列中存在这类请求,那么就直接再次添加相同的请求,就没有必要重新建立一个新的请求了...如果这个请求在批处理队列中并不存在,那么就创建一个新的请求来完成...然后放入RequestQueue中和批处理请求队列中...这样就完成了使用ImageLoader来加载图片数据...
这里使用了LruCache()最近最久未使用算法设立的缓存机制,如果缓存的容量发生了不足,那么直接清除最近最久未被使用的图片缓存...同时每一个Key对应的请求仅仅被放入请求队列一次,对于相同key值的请求,直接从缓存中取出即可,如果缓存内部没有数据,那么通过判断当前是否有这类的请求...如果有,直接进行赋值,如果没有定义一个新的请求...
3.NetWorkImageLoader.java
第三种加载图片的方式...它基于ImageLoader,加载图片也是通过ImageLoader来实现的,只是在一些地方有一定的差异...
package com.android.volley.toolbox; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader.ImageContainer; import com.android.volley.toolbox.ImageLoader.ImageListener; public class NetworkImageView extends ImageView { /** The URL of the network image to load */ private String mUrl; //图片的url /** * Resource ID of the image to be used as a placeholder until the network image is loaded. */ private int mDefaultImageId; //默认图片的ID.. /** * Resource ID of the image to be used if the network response fails. */ private int mErrorImageId; //错误显示的图片... /** Local copy of the ImageLoader. */ private ImageLoader mImageLoader; //图片加载对象... /** Current ImageContainer. (either in-flight or finished) */ private ImageContainer mImageContainer; //ImageContainer对象.. public NetworkImageView(Context context) { this(context, null); } public NetworkImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public NetworkImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } //设置图片的url... public void setImageUrl(String url, ImageLoader imageLoader) { mUrl = url; mImageLoader = imageLoader; // The URL has potentially changed. See if we need to load it. loadImageIfNecessary(false); } //设置默认图片... public void setDefaultImageResId(int defaultImage) { mDefaultImageId = defaultImage; } //设置错误图片... public void setErrorImageResId(int errorImage) { mErrorImageId = errorImage; } //这个函数在OnLauout调用时才被调用...用于加载图片... private void loadImageIfNecessary(final boolean isInLayoutPass) { //获取长度和宽度... int width = getWidth(); int height = getHeight(); boolean isFullyWrapContent = getLayoutParams() != null && getLayoutParams().height == LayoutParams.WRAP_CONTENT && getLayoutParams().width == LayoutParams.WRAP_CONTENT; //如果view控件的大小界限是不确定的,并且还不是wrap_content属性,那么放弃加载... 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. //如果这个url被加载后,view是空的,那么就撤销掉与之相同的所有请求... if (TextUtils.isEmpty(mUrl)) { if (mImageContainer != null) { mImageContainer.cancelRequest(); mImageContainer = null; } setImageBitmap(null); return; } // if there was an old request in this view, check if it needs to be canceled. //如果请求是相同的url,那么直接return,数据的获取由缓存处理... if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { if (mImageContainer.getRequestUrl().equals(mUrl)) { // 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(); setImageBitmap(null); } } // The pre-existing content of this view didn‘t match the current URL. Load the new image // from the network. //如果不满足上述情况,那么就建立一个新的ImageContainer来保存... ImageContainer newContainer = mImageLoader.get(mUrl, new ImageListener() { @Override public void onErrorResponse(VolleyError error) { if (mErrorImageId != 0) { setImageResource(mErrorImageId); } } @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) { setImageBitmap(response.getBitmap()); } else if (mDefaultImageId != 0) { setImageResource(mDefaultImageId); } } }); // update the ImageContainer to be the new bitmap container. mImageContainer = newContainer; } //布局函数调用... @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(); } }
这是源码的实现过程,有些细节上的问题就不进行分析了...我们还是来看一下实例...
package com.example.oop; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.ImageLoader.ImageCache; import com.android.volley.toolbox.NetworkImageView; import com.android.volley.toolbox.Volley; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.support.v4.util.LruCache; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity implements OnClickListener { String url="http://192.168.199.172:8080/JSP/imageview.jpg"; NetworkImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView=(NetworkImageView) findViewById(R.id.network); init(); } public void init(){ RequestQueue queue=Volley.newRequestQueue(MainActivity.this); ImageLoader imageLoader=new ImageLoader(queue, new ImageCache() { LruCache<String,Bitmap>cache=new LruCache<String, Bitmap>(((int) Runtime.getRuntime().maxMemory())/8){ @Override protected int sizeOf(String key,Bitmap bitmap){ return bitmap.getRowBytes()*bitmap.getHeight(); } }; @Override public void putBitmap(String url, Bitmap bitmap) { // TODO Auto-generated method stub cache.put(url, bitmap); } @Override public Bitmap getBitmap(String url) { // TODO Auto-generated method stub return cache.get(url); } }); imageView.setDefaultImageResId(R.drawable.default_image); //这里需要手动设置默认图片和错误显示图片... imageView.setErrorImageResId(R.drawable.no_image); //加载获取图片的过程... imageView.setImageUrl(url, imageLoader); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
需要说的是,布局文件中我们需要这样进行书写去定义一个NetWorkImageView对象...通过获取ID,来进行数据信息的加载...
<com.android.volley.toolbox.NetworkImageView android:id="@+id/network" android:layout_height="100dip" android:layout_width="100dip"> </com.android.volley.toolbox.NetworkImageView>
Android 学习笔记之Volley(八)实现网络图片的数据加载
原文:http://www.cnblogs.com/RGogoing/p/4909598.html