Volley源码分析(2)----ImageLoader

一:imageLoader

先来看看如何使用imageloader:

public void showImg(View view){
    ImageView imageView = (ImageView)this.findViewById(R.id.image_view);
    RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext()); 

    ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());
    ImageListener listener = ImageLoader.getImageListener(imageView,R.drawable.default_image, R.drawable.default_image);
    imageLoader.get("http://developer.android.com/images/home/aw_dac.png", listener);
    //指定图片允许的最大宽度和高度
    //imageLoader.get("http://developer.android.com/images/home/aw_dac.png",listener, 200, 200);
}

ImageLoader操作挺繁琐,但是关键的就一句:

imageLoader.get("http://developer.android.com/images/home/aw_dac.png", listener);

下载图片。

所以我们来分析这句,至于BitmapCache,RequestQueue的作用和目的,在

Volley源码分析(1)----Volley 队列 中已经说明。

/**
     * Issues a bitmap request with the given URL if that image is not available
     * in the cache, and returns a bitmap container that contains all of the data
     * relating to the request (as well as the default image if the requested
     * image is not available).
     * @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.
     * @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) {

        // only fulfill requests that were initiated from the main thread.
        throwIfNotOnMainThread();

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

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

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

确保该申请是在主线程进行的。

如果有cache,就直接返回结果:

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

判断是否有相同的请求正在队列里面,这里和前面volley的缓存十分类似!

最后添加一个imageRequest,放入队列里面。

关于cache的部分.

首先,

imageloader需要传入一个cache的对象,用以存放图片cache,我们称为image cache。

而网络请求队列也放置一个cache,放置网络返回的数据,我们称为request cache.

二:NetworkImageView

public class NetworkImageView extends ImageView 

可以直接使用的基于URL的imageView。

        networkImageView = (NetworkImageView) findViewById(R.id.nivTestView);

        mQueue = Volley.newRequestQueue(this);

        LruImageCache lruImageCache = LruImageCache.instance();

        ImageLoader imageLoader = new ImageLoader(mQueue,lruImageCache);

        networkImageView.setDefaultImageResId(R.drawable.ic_launcher);
        networkImageView.setErrorImageResId(R.drawable.ic_launcher);
        networkImageView.setImageUrl(URLS[1], imageLoader);

使用非常简单,setImageUrl。

networkImageView极有可能时使用在listView 或者GridView等有大量使用的地方。

这里就有2个问题:

1.networkImageView需要在UI线程显示图片,图片的获取无疑是在后台线程的。

2.imageLoader是否可以重用?

我们先看第一个问题:

图片的加载更新在如下方法中,

void loadImageIfNecessary(final boolean isInLayoutPass)

如果URL为空,显示默认图片。

        // if the URL to be loaded in this view is empty, cancel any old requests and clear the
        // currently loaded image.
        if (TextUtils.isEmpty(mUrl)) {
            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(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();
                setDefaultImageOrNull();
            }
        }

查看是否有old request在container中。

这个处理非常有用,在adapterlistView中,往往只是更新局部的内容,而这样就不需要处理,没有必要更新的imageView。

下面的过程就是调用imageloader的过程。

/**
     * 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.
     */
    void loadImageIfNecessary(final boolean isInLayoutPass) {
        int width = getWidth();
        int height = getHeight();
        ScaleType scaleType = getScaleType();

        boolean wrapWidth = false, wrapHeight = false;
        if (getLayoutParams() != null) {
            wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
            wrapHeight = getLayoutParams().height == 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.
        boolean isFullyWrapContent = wrapWidth && wrapHeight;
        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(mUrl)) {
            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(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();
                setDefaultImageOrNull();
            }
        }

        // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
        int maxWidth = wrapWidth ? 0 : width;
        int maxHeight = wrapHeight ? 0 : height;

        // The pre-existing content of this view didn‘t match the current URL. Load the new image
        // from the network.
        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);
                        }
                    }
                }, maxWidth, maxHeight, scaleType);

        // update the ImageContainer to be the new bitmap container.
        mImageContainer = newContainer;
    }

loadImageIfNecessary

2.imageLoader是否可以重用?

imageloader作为一个功能处理类,显然时不会跟一个imageview绑定在一起的。

我们更可以从上述分析的get方法中确定,每次get方法,如果需要都会生成一个imageRequest,所以并不会冲突。

三:Picasso分析

Picasso不仅实现了图片异步加载的功能,还解决了android中加载图片时需要解决的一些常见问题:

1.在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。

2.使用复杂的图片压缩转换来尽可能的减少内存消耗

3.自带内存和硬盘二级缓存功能

我们首先来看看Picasso如何加载一个图片。

首先它有几个加载的方法:

  /**
   * Start an image request using the specified URI.
   * <p>
   * Passing {@code null} as a {@code uri} will not trigger any request but will set a placeholder,
   * if one is specified.
   *
   * @see #load(File)
   * @see #load(String)
   * @see #load(int)
   */
  public RequestCreator load(Uri uri) {
    return new RequestCreator(this, uri, 0);
  }

可以看到,它可以加载 文件,文件路径,资源id,当然还有url。

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

我们看看into方法:

com/squareup/picasso/RequestCreator.java

 /**
   * Asynchronously fulfills the request into the specified {@link ImageView} and invokes the
   * target {@link Callback} if it‘s not {@code null}.
   * <p>
   * <em>Note:</em> The {@link Callback} param is a strong reference and will prevent your
   * {@link android.app.Activity} or {@link android.app.Fragment} from being garbage collected. If
   * you use this method, it is <b>strongly</b> recommended you invoke an adjacent
   * {@link Picasso#cancelRequest(android.widget.ImageView)} call to prevent temporary leaking.
   */
  public void into(ImageView target, Callback callback) {
    long started = System.nanoTime();
    checkMain();

    if (target == null) {
      throw new IllegalArgumentException("Target must not be null.");
    }

    if (!data.hasImage()) {
      picasso.cancelRequest(target);
      if (setPlaceholder) {
        setPlaceholder(target, getPlaceholderDrawable());
      }
      return;
    }

    if (deferred) {
      if (data.hasSize()) {
        throw new IllegalStateException("Fit cannot be used with resize.");
      }
      int width = target.getWidth();
      int height = target.getHeight();
      if (width == 0 || height == 0) {
        if (setPlaceholder) {
          setPlaceholder(target, getPlaceholderDrawable());
        }
        picasso.defer(target, new DeferredRequestCreator(this, target, callback));
        return;
      }
      data.resize(width, height);
    }

    Request request = createRequest(started);
    String requestKey = createKey(request);

    if (!skipMemoryCache) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        picasso.cancelRequest(target);
        setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
        if (picasso.loggingEnabled) {
          log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
        }
        if (callback != null) {
          callback.onSuccess();
        }
        return;
      }
    }

    if (setPlaceholder) {
      setPlaceholder(target, getPlaceholderDrawable());
    }

    Action action =
        new ImageViewAction(picasso, target, request, skipMemoryCache, noFade, errorResId,
            errorDrawable, requestKey, tag, callback);

    picasso.enqueueAndSubmit(action);
  }

into

一开始也是判断主线程,和Volley的networkImageView相同。

判断传入的uri,或者resourceid是否有问题。

不对,就取消这次请求。

下面就是调整图片请求的大小。

    if (deferred) {
      if (data.hasSize()) {
        throw new IllegalStateException("Fit cannot be used with resize.");
      }
      int width = target.getWidth();
      int height = target.getHeight();
      if (width == 0 || height == 0) {
        if (setPlaceholder) {
          setPlaceholder(target, getPlaceholderDrawable());
        }
        picasso.defer(target, new DeferredRequestCreator(this, target, callback));
        return;
      }
      data.resize(width, height);
    }

这段不重要,我们继续看下去:

    Request request = createRequest(started);
    String requestKey = createKey(request);

 /** Create the request optionally passing it through the request transformer. */
  private Request createRequest(long started) {
    int id = getRequestId();

    Request request = data.build();
    request.id = id;
    request.started = started;

    boolean loggingEnabled = picasso.loggingEnabled;
    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
    }

    Request transformed = picasso.transformRequest(request);
    if (transformed != request) {
      // If the request was changed, copy over the id and timestamp from the original.
      transformed.id = id;
      transformed.started = started;

      if (loggingEnabled) {
        log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
      }
    }

    return transformed;
  }

createRequest

首先是配置id,和starttime,这个可以定位request。

requestKey其实就是一套方法用于区分request,更重要的是,获取缓存。

默认使用的memory cache 为LruCache。

此处可以imageLoader(指Volley里面的imageloader,下同)做比较,imageLoader一般使用BitmapCache

作为内存缓存,文件缓存有vollley requestQueue做处理。所以从结构上来说,Picasso和imageLoader是相似的。

接下来就是从LruCache中获取图片。

    if (!skipMemoryCache) {
      Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
      if (bitmap != null) {
        picasso.cancelRequest(target);
        target.onBitmapLoaded(bitmap, MEMORY);
        return;
      }
    }

不需考虑,Picasso肯定也有请求队列,他是通过android的handle-thread的方式来驱动的。

  void submit(Action action) {
    dispatcher.dispatchSubmit(action);
  }
  void dispatchSubmit(Action action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
  }
    @Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case REQUEST_SUBMIT: {
          Action action = (Action) msg.obj;
          dispatcher.performSubmit(action);
          break;
        }

该handler是在异步线程里面处理消息。

然后dispatcher.performSubmit(action);会在线程池中PicassoExecutorService启动task。

接着我们看com/squareup/picasso/BitmapHunter.java:

网络请求的,应该在这里处理。

Bitmap hunt() throws IOException {
    Bitmap bitmap = null;

    if (!skipMemoryCache) {
      bitmap = cache.get(key);
      if (bitmap != null) {
        stats.dispatchCacheHit();
        loadedFrom = MEMORY;
        if (picasso.loggingEnabled) {
          log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
        }
        return bitmap;
      }
    }

    data.loadFromLocalCacheOnly = (retryCount == 0);
    RequestHandler.Result result = requestHandler.load(data);
    if (result != null) {
      bitmap = result.getBitmap();
      loadedFrom = result.getLoadedFrom();
      exifRotation = result.getExifOrientation();
    }

    if (bitmap != null) {
      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_DECODED, data.logId());
      }
      stats.dispatchBitmapDecoded(bitmap);
      if (data.needsTransformation() || exifRotation != 0) {
        synchronized (DECODE_LOCK) {
          if (data.needsMatrixTransform() || exifRotation != 0) {
            bitmap = transformResult(data, bitmap, exifRotation);
            if (picasso.loggingEnabled) {
              log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
            }
          }
          if (data.hasCustomTransformations()) {
            bitmap = applyCustomTransformations(data.transformations, bitmap);
            if (picasso.loggingEnabled) {
              log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
            }
          }
        }
        if (bitmap != null) {
          stats.dispatchBitmapTransformed(bitmap);
        }
      }
    }

    return bitmap;
  }

开始还是从memory cache中获取。

在hunt方法中,

    RequestHandler.Result result = requestHandler.load(data);

这句就是图片获取的过程。

但是这个requestHandler究竟是什么?

从头看,在Picasso构造函数里面有:

    allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
    allRequestHandlers.add(new MediaStoreRequestHandler(context));
    allRequestHandlers.add(new ContentStreamRequestHandler(context));
    allRequestHandlers.add(new AssetRequestHandler(context));
    allRequestHandlers.add(new FileRequestHandler(context));
    allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));

所以,requestHandler可能就是上面一个里面的一个。

我们就看FileRequestHandler。

  @Override public boolean canHandleRequest(Request data) {
    return SCHEME_FILE.equals(data.uri.getScheme());
  }

也就是,FileRequestHandler只处理file类型的请求。

所以从网络获取图片com/squareup/picasso/NetworkRequestHandler.java:

直接看load:

@Override public Result load(Request data) throws IOException {
    Response response = downloader.load(data.uri, data.loadFromLocalCacheOnly);
    if (response == null) {
      return null;
    }

    Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;

    Bitmap bitmap = response.getBitmap();
    if (bitmap != null) {
      return new Result(bitmap, loadedFrom);
    }

    InputStream is = response.getInputStream();
    if (is == null) {
      return null;
    }
    // Sometimes response content length is zero when requests are being replayed. Haven‘t found
    // root cause to this but retrying the request seems safe to do so.
    if (response.getContentLength() == 0) {
      Utils.closeQuietly(is);
      throw new IOException("Received response with 0 content-length header.");
    }
    if (loadedFrom == NETWORK && response.getContentLength() > 0) {
      stats.dispatchDownloadFinished(response.getContentLength());
    }
    try {
      return new Result(decodeStream(is, data), loadedFrom);
    } finally {
      Utils.closeQuietly(is);
    }
  }

load

      if (downloader == null) {
        downloader = Utils.createDefaultDownloader(context);
      }

download是在build里面创建的,其实很多内容都是在这里面创建的。

 public Picasso build()

最终获取的downloader对象是HttpURLConnection来进行网络通信。

我们看到response的结果是2种,DISK : NETWORK。

所以我们分析如何得到这2种结果,整个picasso的图片加载过程也就结束了。

1.UrlConnectionDownloader:

 @Override public Response load(Uri uri, boolean localCacheOnly) throws IOException {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      installCacheIfNeeded(context);
    }

    HttpURLConnection connection = openConnection(uri);
    connection.setUseCaches(true);
    if (localCacheOnly) {
      connection.setRequestProperty("Cache-Control", "only-if-cached,max-age=" + Integer.MAX_VALUE);
    }

    int responseCode = connection.getResponseCode();
    if (responseCode >= 300) {
      connection.disconnect();
      throw new ResponseException(responseCode + " " + connection.getResponseMessage());
    }

    long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
    boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));

    return new Response(connection.getInputStream(), fromCache, contentLength);
  }

通过HttpUrlConnection的cache,来得到结果,以及fromCache。

2.OkHttpDownloader

@Override public Response load(Uri uri, boolean localCacheOnly) throws IOException {
    HttpURLConnection connection = openConnection(uri);
    connection.setUseCaches(true);
    if (localCacheOnly) {
      connection.setRequestProperty("Cache-Control", "only-if-cached,max-age=" + Integer.MAX_VALUE);
    }

    int responseCode = connection.getResponseCode();
    if (responseCode >= 300) {
      connection.disconnect();
      throw new ResponseException(responseCode + " " + connection.getResponseMessage());
    }

    String responseSource = connection.getHeaderField(RESPONSE_SOURCE_OKHTTP);
    if (responseSource == null) {
      responseSource = connection.getHeaderField(RESPONSE_SOURCE_ANDROID);
    }

    long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
    boolean fromCache = parseResponseSourceHeader(responseSource);

    return new Response(connection.getInputStream(), fromCache, contentLength);
  }

过程类似。

至此,一个完整的获取图片的流程就可以看到了。

1.每一条图片请求将会包装成一个request。

2.每一个request将会submit到一个DispatcherThread的线程做分发操作。

3.找到request对应的RequestHandler。把bitmaphunter放入PicassoExecutorService线程池里面。

4.由不同的RequestHandler来处理各种情况,包括网络request。

5.剩下的就是结果的处理,和delivier response的过程了。

由于本文只关心网络图片的加载过程,所以只涉及了Picasso的2级缓存功能。

参考:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0731/1639.html

http://square.github.io/picasso/

本系列第一篇:Volley源码分析(1)----Volley 队列

时间: 2024-10-10 23:30:19

Volley源码分析(2)----ImageLoader的相关文章

[Android]Volley源码分析(肆)应用

通过前面的讲述,相信你已经对Volley的原理有了一定了解.本章将举一些我们能在应用中直接用到的例子,第一个例子是 NetworkImageView类,其实NetworkImageView顾名思义就是将异步的操作封装在了控件本身,这种设计可以充分保留控件的移植性和维护性.NetworkImageView通过调用setImageUrl来指定具体的url: public void setImageUrl(String url, ImageLoader imageLoader) { mUrl = ur

Volley源码分析二

在前两天我发布的文章:Volley源码分析一 中我较为详细的分析了Volley,今天继续,这篇文章会讲一些上一篇没有提到的比较细节的点,以及对于Volley源码中一些可以优化的实现的一些思考 ByteArrayPool的分析 byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收.主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素. public synchronized

[Android]Volley源码分析(四)

上篇中有提到NetworkDispatcher是通过mNetwork(Network类型)来进行网络访问的,现在来看一下关于Network是如何进行网络访问的. Network部分的类图: Network有一个实现类BasicNetwork,它有一个mHttpStack的属性,实际的网络请求是由这个mHttpStack来进行的,看BasicNetwork的performRequest()方法, 1 @Override 2 public NetworkResponse performRequest

Volley源码分析

Volley源码分析 Volley简介 volley官方地址 在Google I/0 2013中发布了Volley.Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮. 这是Volley名称的由来:a burst or emission of many things or a large amount at once.Volley特别适合数据量不大但是通信频繁的场景. Github上面已经有大神做了镜像,使用Gradle更方便.Volley On Github Vo

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

[Android]Volley源码分析(叁)Network

如果各位看官仔细看过我之前的文章,实际上Network这块的只是点小功能的补充.我们来看下NetworkDispatcher的核心处理逻辑: <span style="font-size:18px;">while (true) { try { // Take a request from the queue. request = mQueue.take(); } catch (InterruptedException e) { // We may have been int

[Android] Volley源码分析(一)体系结构

Volley:google出的一个用于异步处理的框架.由于本身的易用性和良好的api,使得它能得以广泛的应用.我还是一如既往从源码的方向上来把控它.我们先通过一段简单的代码来了解Volley RequestQueue queue = Volley.newRequestQueue(this); ImageRequest imagerequest = new ImageRequest(url, new Response.Listener<Bitmap>(){ @Override public vo

Volley源码分析之自定义MultiPartRequest(文件上传)

本篇内容目录: 使用HttpURLConnection上传文件到服务器案例 自定义支持文件上传的MultiPartRequest Web后台接收文件的部分代码 先来看下HttpURLConnection来文件上传的案例: 1.传送数据到服务器,必定是使用POST请求: //设置请求方式为post httpURLConnection.setDoOutput(true); httpURLConnection.setRequestMethod("POST"); 2.上传文件的HTTP请求中的

[Android]Volley源码分析(五)

前面几篇通过源码分析了Volley是怎样进行请求调度及请求是如何被实际执行的,这篇最后来看下请求结果是如何交付给请求者的(一般是Android的UI主线程). 类图: 请求结果的交付是通过ResponseDelivery接口完成的,它有一个实现类ExecutorDelivery, 主要有postResponse()与postError()两个方法,分别在请求成功或失败时将结果提交给请求发起者. 1. 首先,在NetworkDispatcher的run()方法中,当服务器返回响应并解析完后,会调用