Volley源码分析

Request中的子类:
- ClearCacheRequest
- ImageRequest
- JsonArrayRequest
- JsonObjectRequest
- JsonRequest
- StringRequest


Request中的网络请求方式:
int GET = 0 ;
int POST = 1 ;
int PUT = 2 ;
int DELETE = 3;
int HEAD = 4 ;
int OPTIONS = 5;
int TRACE = 6 ;
int PATCH = 7 ;
ImageRequest一共有三个构造方法:
1.
  * @param url URL of the image
* @param listener Listener to receive the decoded bitmap
* @param maxWidth Maximum width to decode this bitmap to, or zero for none
* @param maxHeight Maximum height to decode this bitmap to, or zero for
*            none
* @param decodeConfig Format to decode the bitmap to
* @param errorListener Error listener, or null to ignore errors
*/
public ImageRequest(String url, Response.Listener<Bitmap> listener , int maxWidth, int maxHeight,
                    Config decodeConfig, Response.ErrorListener errorListener) {
    this (url, listener , maxWidth, maxHeight, ScaleType. CENTER_INSIDE, decodeConfig, null, errorListener) ;
}
2:
  * @param url URL of the image
* @param listener Listener to receive the decoded bitmap
* @param maxWidth Maximum width to decode this bitmap to, or zero for none
* @param maxHeight Maximum height to decode this bitmap to, or zero for
*            none
* @param scaleType The ImageViews ScaleType used to calculate the needed image size.
* @param decodeConfig Format to decode the bitmap to
* @param errorListener Error listener, or null to ignore errors
*/
public ImageRequest(String url, Response.Listener<Bitmap> listener , int maxWidth, int maxHeight,
        ScaleType scaleType , Config decodeConfig, Response.ErrorListener errorListener) {
    this (url, listener , maxWidth, maxHeight, scaleType , decodeConfig, null, errorListener);
}

3:
  * @param url            URL of the image
* @param listener       Listener to receive the decoded bitmap
* @param maxWidth       Maximum width to decode this bitmap to, or zero for none
* @param maxHeight      Maximum height to decode this bitmap to, or zero for
*                       none
* @param scaleType      The ImageViews ScaleType used to calculate the needed image size.
* @param decodeConfig   Format to decode the bitmap to
* @param transformation Image transformation
* @param errorListener  Error listener, or null to ignore errors
*/
public ImageRequest(String url, Response.Listener<Bitmap> listener , int maxWidth, int maxHeight,
                    ScaleType scaleType, Config decodeConfig, Transformation transformation, 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;
    mScaleType = scaleType;
    mTransformation = transformation;
}

1:ImageRequest会进行一些图片的操作,比如根据传递进来的ScaleType进行图片的处理,获取图片的最合适的尺寸(方法就是:getResizedDimension()方法)。
2:里面有一个parseNetworkResponse方法会调用都Parse()方法,这个方法需要一个参数就是NwtworkResponse,在这里将会根据之前构造方法中传递进来的maxWidth或者是maxHeight进行处理,如果是0,那么将会返回一个正常的没有处理过的图片,但是如果有数值那么就会对bitmap进行处理也就是常说的二次采样,做法如下:
private Response<Bitmap> doParse(NetworkResponse response) {
    byte[] data = response.data;
    BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
    Bitmap bitmap = null;
    if (mMaxWidth == 0 && mMaxHeight == 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, mScaleType);
        int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
                actualHeight, actualWidth, mScaleType);

        // 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 && desiredWidth > 0 && desiredHeight > 0 &&
                (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 {
        if (mTransformation != null)
            bitmap = mTransformation.transform(bitmap, mMaxWidth, mMaxHeight);
        return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
    }
}

二、下面我们说下RequestQueue:

1、里面有这么一条:
/** Number of network request dispatcher threads to start. */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
也就是说会默认的有四个线程去启动进行异步网络数据的获取
2、我们一般使用RequestQueue使用的是:
 Volley.newInstance(Context context,HttpSocket (这个可以不要))返回一个RequestQueue
public static RequestQueue newRequestQueue(Context context , HttpStack stack) {
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR) ;

    String userAgent = "volley/0";
    try {
        String packageName = context.getPackageName();
        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
        userAgent = packageName + "/" + info.versionCode ;
    } catch (NameNotFoundException e) {
    }

    if (stack == null) {
        if (Build.VERSION.SDK_INT >= 9) {
            stack = new HurlStack();
        } else {
            // Prior to Gingerbread, HttpUrlConnection was unreliable.
            // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
        }
    }

    Network network = new BasicNetwork(stack);

    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    queue.start() ;

    return queue ;
}

在这之后我们发现他会自己创建一个缓存目录点进去会看出来默认的目录就是:volley
所以我们的缓存是放在data/data/volley中的。如果我们调用Volley的一个参数的构造方法那么volley就默认调用两个构造方法的构造函数,第二个参数是null。

RequestQueue的构造方法:
/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*
* @param cache A Cache to use for persisting responses to disk
* @param network A Network interface for performing HTTP requests
* @param threadPoolSize Number of network dispatcher threads to create
*/
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
    this (cache, network , threadPoolSize,
            new ExecutorDelivery( new Handler(Looper.getMainLooper ())));
}

/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*
* @param cache A Cache to use for persisting responses to disk
* @param network A Network interface for performing HTTP requests
*/
public RequestQueue(Cache cache, Network network) {
    this (cache, network , DEFAULT_NETWORK_THREAD_POOL_SIZE);
}

然后就是NetworkDispatcher的启动添加request或者是移除request在添加或者是移除的时候将会对其进行加锁操作。

三、ImageLoader的源码:
里面有一个:
/**
* Simple cache adapter interface. If provided to the ImageLoader, it
* will be used as an L1 cache before dispatch to Volley. Implementations
* must not block. Implementation with an LruCache is recommended.
*/
public interface ImageCache {
    public Bitmap getBitmap(String url) ;
    public void putBitmap (String url, Bitmap bitmap) ;
}

用来进行缓存的ImageCache接口如果想要实现自定义缓存以及路径系要实现这个接口
ImageLoader的构造方法:
/**
* Constructs a new ImageLoader.
* @param queue The RequestQueue to use for making image requests.
* @param imageCache The cache to use as an L1 cache.
*/
public ImageLoader(RequestQueue queue, ImageCache imageCache) {
    mRequestQueue = queue;
    mCache = imageCache;
}



在下面这个方法中封装了IamgeQueue:
  * @param requestUrl The url of the remote image
* @param imageListener The listener to call when the remote image is loaded
* @param maxWidth The maximum width of the returned image.
* @param maxHeight The maximum height of the returned image.
* @param scaleType The ImageViews ScaleType used to calculate the needed image size.
* @param transformation Image transformation.
* @return A container object that contains all of the properties of the request, as well as
*     the currently available image (default if remote is not loaded).
*/
public ImageContainer get (String requestUrl, ImageListener imageListener ,
                          int maxWidth, int maxHeight , ScaleType scaleType,
                          ImageRequest.Transformation transformation) {
   
    // only fulfill requests that were initiated from the main thread.
    throwIfNotOnMainThread() ;

    final String cacheKey = getCacheKey(requestUrl , maxWidth, maxHeight, scaleType, transformation) ;

    // Try to look up the request in the cache of remote images.
    Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
    if (cachedBitmap != null) {
        // Return the cached bitmap.
        ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
        imageListener.onResponse(container , true);
        return container ;
    }

    // The bitmap did not exist in the cache, fetch it!
    ImageContainer imageContainer =
            new ImageContainer(null, requestUrl , cacheKey, imageListener);

    // 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 ;
    }

    // The request is not already in flight. Send the new request to the network and
    // track it.
    Request<Bitmap> newRequest = makeImageRequest(requestUrl , maxWidth, maxHeight, scaleType ,
            cacheKey , transformation);

    mRequestQueue .add(newRequest);
    mInFlightRequests .put(cacheKey,
            new BatchedImageRequest(newRequest , imageContainer));
    return imageContainer ;
}

protected Request<Bitmap> makeImageRequest(String requestUrl , int maxWidth, int maxHeight,
                                           ScaleType scaleType, final String cacheKey ,
                                           final ImageRequest.Transformation transformation) {
    return new ImageRequest(requestUrl, new Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            onGetImageSuccess(cacheKey, response);
        }
    }, maxWidth, maxHeight , scaleType, Config.RGB_565, transformation, new ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            onGetImageError(cacheKey, error);
        }
    });
}

可以通过下面的方法获取bitmap:
getImageBitmap()

通过这个方法获取Listener:
* @param defaultImageResId Default image resource ID to use, or 0 if it doesn't exist.
* @param errorImageResId Error image resource ID to use, or 0 if it doesn't exist.
*/
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);
            }
        }
    };
}











你可能感兴趣的:(源码,Volley)