澳门新莆京手机网站-新蒲京娱乐场 > 书籍 > 【澳门新莆京手机网站】Android_图片加载库

【澳门新莆京手机网站】Android_图片加载库

图片加载在Android开辟中是老大首要,好的图样加载库也俯拾便是。ImageLoader、Picasso、Glide、Fresco均是不错的图纸加载库。

Picasso.with(this).load("").placeholder(R.mipmap.ic_launcher).into(imageView);

Picasso是叁个由Square集团开源的强有力的Android图片下载缓存库,仅仅只要求生机勃勃行代码就足以兑现图片的异步加载。

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

Picasso还消除了Android加载图片时索要缓和的朝气蓬勃部分大范围难题:

  • 在adapter中撤消不在显示屏范围内的ImageView图片的加载
  • 选取复杂的图形转变成尽恐怕裁减内部存款和储蓄器消耗
  • 自带内部存款和储蓄器和硬盘的二级缓存

接收样例:

  1. Adapter中下载: 艾达pter的录用会被自动质量评定到,Picasso会撤消上次的加载
@Override public void getView(int position, View convertView, ViewGroup parent) {
  SquaredImageView view = (SquaredImageView) convertView;
  if (view == null) {
    view = new SquaredImageView(context);
  }
  String url = getItem(position);

  Picasso.with(context).load(url).into(view);
}

2.图纸调换:调换图片以适应布局大小并减削内部存款和储蓄器占用

Picasso.with(context)
  .load(url)
  .resize(50, 50)
  .centerCrop()
  .into(imageView)

3.自定义转变

public class CropSquareTransformation implements Transformation {
  @Override public Bitmap transform(Bitmap source) {
    int size = Math.min(source.getWidth(), source.getHeight());
    int x = (source.getWidth() - size) / 2;
    int y = (source.getHeight() - size) / 2;
    Bitmap result = Bitmap.createBitmap(source, x, y, size, size);
    if (result != source) {
      source.recycle();
    }
    return result;
  }

  @Override public String key() { return "square()"; }
}

4.PlaceHolders: 空白或然不当占位图片:picasso提供了二种占位图片,未加载成功大概加载产生错误的时须要一张图片作为提示

Picasso.with(context)
    .load(url)
    .placeholder(R.drawable.user_placeholder)
    .error(R.drawable.user_placeholder_error)
    .into(imageView);

5.能源文件加载: 除了加载互连网图片picasso还帮忙加载Resources, assets, files, content providers中的能源文件

Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);
Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2);
Picasso.with(context).load(new File(...)).into(imageView3);

6.调整提醒:对开拓者来讲,在Picasso实例中调用setIndicatorsEnabled(true卡塔尔国方法,展览会示红、绿、蓝三种颜色的色带给表示分别从网络、内部存储器、硬盘中加载的财富

澳门新莆京手机网站 1

picasso.PNG

  1. 伸手分发模块。担负打包央浼,对央求实行事情发生前级排序,并根据种类举办分发。
  2. 缓存模块。平时包含一个二级的缓存,内部存款和储蓄器缓存、磁盘缓存。并预置七种缓存战略。
  3. 下载模块。担任下载网络图片。
  4. 监理模块。负担督察缓存命中率、内存占用、加载图片平均耗费时间等。
  5. 图片处理模块。担任对图片举行压缩、转换等管理。
  6. 本地财富加载模块。担负加载本地能源,如assert、drawable、sdcard等。
    7.显得模块。担当将图纸输出显示。

以上关联的两种图片加载库各有特色。用法与相比较,网霜月经重重了。

那是四个Picasso的利用格局,从此间出手来看看Picasso的源码布局格局

Picasso中多少个首要的类介绍:

LruCache

static int calculateMemoryCacheSize(Context context) {
    ActivityManager am = getService(context, ACTIVITY_SERVICE);
    boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
    int memoryClass = largeHeap ? am.getLargeMemoryClass() : am.getMemoryClass();
    // Target ~15% of the available heap.
    return (int) (1024L * 1024L * memoryClass / 7);
  }

LrcCache内部存款和储蓄器占用了动用能够行使的最大内部存款和储蓄器的 1/7(约为15%)。

static File createDefaultCacheDir(Context context) {
    File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE);
    if (!cache.exists()) {
      //noinspection ResultOfMethodCallIgnored
      cache.mkdirs();
    }
    return cache;
  }

在初阶化OkHttp3Downloader时,picasso会创制磁盘缓存的文件夹,在 /data/data/应用包名/cache/picasso-cache 目录下。

@TargetApi(JELLY_BEAN_MR2)
  static long calculateDiskCacheSize(File dir) {
    long size = MIN_DISK_CACHE_SIZE;

    try {
      StatFs statFs = new StatFs(dir.getAbsolutePath());
      //noinspection deprecation
      long blockCount =
          SDK_INT < JELLY_BEAN_MR2 ? (long) statFs.getBlockCount() : statFs.getBlockCountLong();
      //noinspection deprecation
      long blockSize =
          SDK_INT < JELLY_BEAN_MR2 ? (long) statFs.getBlockSize() : statFs.getBlockSizeLong();
      long available = blockCount * blockSize;
      // Target 2% of the total space.
      size = available / 50;
    } catch (IllegalArgumentException ignored) {
    }

    // Bound inside min/max size for disk cache.
    return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
  }

Picasso会调节占用磁盘缓存的深浅决定在5M~50M之间

public LruCache(int maxSize) {
    if (maxSize <= 0) {
      throw new IllegalArgumentException("Max size must be positive.");
    }
    this.maxSize = maxSize;
    this.map = new LinkedHashMap<>(0, 0.75f, true);
  }

LinkedHashMap<>(int initialCapacity,float loadFactor,boolean accessOrder卡塔尔(قطر‎ 结构方法参数含义:
initialCapacity:最早体量大小,使用无参布局方法时,此值默许是16
loadFactor:加载因子,使用无参构造方法时,此值暗中认可是 0.75f
accessOrder false: 基于插入顺序 true: 基于访谈顺序 (使用了LRU 近些日子起码被选取的调度算法)

PicassoExecutorService

void adjustThreadCount(NetworkInfo info) {
    if (info == null || !info.isConnectedOrConnecting()) {
      setThreadCount(DEFAULT_THREAD_COUNT);
      return;
    }
    switch (info.getType()) {
      case ConnectivityManager.TYPE_WIFI:
      case ConnectivityManager.TYPE_WIMAX:
      case ConnectivityManager.TYPE_ETHERNET:
        setThreadCount(4);
        break;
      case ConnectivityManager.TYPE_MOBILE:
        switch (info.getSubtype()) {
          case TelephonyManager.NETWORK_TYPE_LTE:  // 4G
          case TelephonyManager.NETWORK_TYPE_HSPAP:
          case TelephonyManager.NETWORK_TYPE_EHRPD:
            setThreadCount(3);
            break;
          case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
          case TelephonyManager.NETWORK_TYPE_CDMA:
          case TelephonyManager.NETWORK_TYPE_EVDO_0:
          case TelephonyManager.NETWORK_TYPE_EVDO_A:
          case TelephonyManager.NETWORK_TYPE_EVDO_B:
            setThreadCount(2);
            break;
          case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
          case TelephonyManager.NETWORK_TYPE_EDGE:
            setThreadCount(1);
            break;
          default:
            setThreadCount(DEFAULT_THREAD_COUNT);
        }
        break;
      default:
        setThreadCount(DEFAULT_THREAD_COUNT);
    }
  }

PicassoExecutor瑟维斯是Picasso自身封装的线程池,能够看来Wify和以太网景况下设置的线程数量是4,4G网络条件下设置的线程数量是3,3G互连网条件下设置的线程数量是2,2G网络条件下设置的线程数量是1,默许意况下设置的线程数量是3。

Request
装进了风流倜傥多种的对图纸的操作,比如退换图片大小、旋转图片、自定义转换等。

RequestCreator
应用Request.Builder创制了Request对象,后续对RequestCreator的装置都意义在Request对象中。

RequestHandler
抽象类,由区别的子类来达成不一致来源的图样的拿走与加载
完毕类有:
AssetRequestHandler:加载asset里的图样
FileRequestHandler:加载硬盘里的图样
ResourceRequestHandler:加载财富图形
NetworkRequestHandler:加载网络图片

Action
Action代表了三个现实的加载职责,首要用以图片加载后的结果回调,有八个抽象方法,complete和error,也正是当图片剖析为bitmap后顾客愿意做怎么着。最简易的正是将bitmap设置给imageview,失利了就将错误通过回调文告到上层。
现实完结类有:
1.GetAction:同步进行央求时利用。
2.FetchAction:当无需ImageView来安置bitmap时的异步央求,经常用来预热缓存
3.RemoteViewsAction:用来更新远程图片(notification等)的抽象类。
4.TargetAction:经常在View(不只是ImageView)或许ViewHolder中用来加载图片,要求得以达成Target接口
5.ImageViewAction:最常用的Action,首要用来给ImageView加载图片

BitmapHunter
BitmapHunter完毕了Runnable,将经过线程池下载和深入分析图片(hunt and decodeStream)。

Dispatcher
在Bitmaphunter成功获得bitmap后,dispatcher利用Handler机制担任对各样风云举行分发。

Stats
特别用来总括的类,负责将计算的多少发给Dispatcher管理

澳门新莆京手机网站 2

由于学习的角度,个人感到从Picasso动手较好。代码量小,同时API精粹,很契合我们上学。

先是看一下Picasso.with(State of Qatar方法,如下

Picasso代码流程解析:

Picasso源码下载地址:https://github.com/square/picasso

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

咱俩来深入分析一下Picasso是怎么样将一张网络图片下载并加载到ImageView中的

public static Picasso with(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("context == null");
    }
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
          singleton = new Builder(context).build();
        }
      }
    }
    return singleton;
  }

先是在Picasso类中找到 with(State of Qatar 方法,开采Picasso使用Builder(卡塔尔(قطر‎.build(卡塔尔(قطر‎来创立单例的Picasso对象,真正开端化Picasso的操作在 build(State of Qatar 方法中。

public Picasso build() {
      Context context = this.context;

      //Picasso依赖了OKHttp3,使用OkHttp来进行网络操作
      if (downloader == null) {
        downloader = new OkHttp3Downloader(context);
      }
      //使用LruChche缓存
      if (cache == null) {
        cache = new LruCache(context);
      }
      //自定义线程池
      if (service == null) {
        service = new PicassoExecutorService();
      }
      //初始化自定义的Transformer对象(用户对图片的自定义转换)
      if (transformer == null) {
        transformer = RequestTransformer.IDENTITY;
      }

      //状态控制类,用来发送各种消息,例如查找图片缓存的结果(击中/未击中),下载完成等
      Stats stats = new Stats(cache);

      //内部使用handler传递消息
      Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }
  }

在 build(State of Qatar 中大家能够见见Picasso实例化了 OkHttp3Downloader、LruCache、PicassoExecutorService、Stats、Dispatcher,最后回来Picasso对象。

public RequestCreator load(@Nullable String path) {
    if (path == null) {
      return new RequestCreator(this, null, 0);
    }
    if (path.trim().length() == 0) {
      throw new IllegalArgumentException("Path must not be empty.");
    }
    return load(Uri.parse(path));
  }

奉行完with(卡塔尔(قطر‎ ,我们再来看 load(State of Qatar,开掘Picasso将图片地址传入重返了贰个RequestCreator 对象。

RequestCreator(Picasso picasso, Uri uri, int resourceId) {
    if (picasso.shutdown) {
      throw new IllegalStateException(
          "Picasso instance already shut down. Cannot submit new requests.");
    }
    this.picasso = picasso;
    this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
  }

private Request createRequest(long started) {
    int id = nextId.getAndIncrement();

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

RequestCreator中的 createRequest(卡塔尔国 同样的采纳 Builder(卡塔尔国.build(State of Qatar 创设了 Request 类对象。

public Request build() {
      if (centerInside && centerCrop) {
        throw new IllegalStateException("Center crop and center inside can not be used together.");
      }
      if (centerCrop && (targetWidth == 0 && targetHeight == 0)) {
        throw new IllegalStateException(
            "Center crop requires calling resize with positive width and height.");
      }
      if (centerInside && (targetWidth == 0 && targetHeight == 0)) {
        throw new IllegalStateException(
            "Center inside requires calling resize with positive width and height.");
      }
      if (priority == null) {
        priority = Priority.NORMAL;
      }
      return new Request(uri, resourceId, stableKey, transformations, targetWidth, targetHeight,
          centerCrop, centerInside, centerCropGravity, onlyScaleDown, rotationDegrees,
          rotationPivotX, rotationPivotY, hasRotationPivot, purgeable, config, priority);
    }

到 Request 类中查阅 build(State of Qatar 方法。

public RequestCreator placeholder(@DrawableRes int placeholderResId) {
    if (!setPlaceholder) {
      throw new IllegalStateException("Already explicitly declared as no placeholder.");
    }
    if (placeholderResId == 0) {
      throw new IllegalArgumentException("Placeholder image resource invalid.");
    }
    if (placeholderDrawable != null) {
      throw new IllegalStateException("Placeholder image already set.");
    }
    this.placeholderResId = placeholderResId;
    return this;
  }

使用 placeholder 来设置暗许图片

public RequestCreator error(@NonNull Drawable errorDrawable) {
    if (errorDrawable == null) {
      throw new IllegalArgumentException("Error image may not be null.");
    }
    if (errorResId != 0) {
      throw new IllegalStateException("Error image already set.");
    }
    this.errorDrawable = errorDrawable;
    return this;
  }

运用 error 来安装出错开上下班时间的图样

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 || target.isLayoutRequested()) {
        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 (shouldReadFromMemoryCache(memoryPolicy)) {
      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, memoryPolicy, networkPolicy, errorResId,
            errorDrawable, requestKey, tag, callback, noFade);

    picasso.enqueueAndSubmit(action);
  }

接下去看看最终的 into(State of Qatar方法,那个形式正是向ImageView中设置图片财富了,所以率先检查是否在主线程,不在主线程抛非常。再检查评定imageview 是不是为空,为空抛非凡。再看是否有设置图片资源的uri和resourceId,若无则打消恳求,假若设置了placeholder,则将plackholder中的能源设置到 imageView 中。当尝试调节图片的尺寸让其刚巧合乎ImageView时,也正是调用了 fit(卡塔尔 方法时(deferred为true卡塔尔(قطر‎,就调用 resize(卡塔尔国调节图片的大小。然后创设Request,依据Request创制requestKey。假若急需从缓存中取数据,就在Cache缓存中根据requestKey来查询缓存的bitmap,即便查询到的bitmap不为空,则在imageView中设置查到的 bitmap,然后调用CallBack的onSuccess(卡塔尔(قطر‎回调方法。假设不是从缓存中取数据,就先安装placeholder中的图片,然后创造ImageViewAction对象,去实践picasso类的 enqueueAndSubmit(卡塔尔(قطر‎ 方法。

void enqueueAndSubmit(Action action) {
    Object target = action.getTarget();
    if (target != null && targetToAction.get(target) != action) {
      // This will also check we are on the main thread.
      cancelExistingRequest(target);
      targetToAction.put(target, action);
    }
    submit(action);
  }

然后是submit() 方法

void submit(Action action) {
    dispatcher.dispatchSubmit(action);
  }

后边正是 Dispatcher类中的 dispatchSubmit(卡塔尔 方法

void dispatchSubmit(Action action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
  }

DispatcherHandler 类的 handleMessage() 方法

@Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case REQUEST_SUBMIT: {
          Action action = (Action) msg.obj;
          dispatcher.performSubmit(action);
          break;
        }
        case REQUEST_CANCEL: {
          Action action = (Action) msg.obj;
          dispatcher.performCancel(action);
          break;
        }
        case TAG_PAUSE: {
          Object tag = msg.obj;
          dispatcher.performPauseTag(tag);
          break;
        }
        case TAG_RESUME: {
          Object tag = msg.obj;
          dispatcher.performResumeTag(tag);
          break;
        }
        case HUNTER_COMPLETE: {
          BitmapHunter hunter = (BitmapHunter) msg.obj;
          dispatcher.performComplete(hunter);
          break;
        }
        case HUNTER_RETRY: {
          BitmapHunter hunter = (BitmapHunter) msg.obj;
          dispatcher.performRetry(hunter);
          break;
        }
        case HUNTER_DECODE_FAILED: {
          BitmapHunter hunter = (BitmapHunter) msg.obj;
          dispatcher.performError(hunter, false);
          break;
        }
        case HUNTER_DELAY_NEXT_BATCH: {
          dispatcher.performBatchComplete();
          break;
        }
        case NETWORK_STATE_CHANGE: {
          NetworkInfo info = (NetworkInfo) msg.obj;
          dispatcher.performNetworkStateChange(info);
          break;
        }
        case AIRPLANE_MODE_CHANGE: {
          dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
          break;
        }
        default:
          Picasso.HANDLER.post(new Runnable() {
            @Override public void run() {
              throw new AssertionError("Unknown handler message received: " + msg.what);
            }
          });
      }
    }

谈到底调到 performSubmit(卡塔尔 方法

void performSubmit(Action action, boolean dismissFailed) {
    if (pausedTags.contains(action.getTag())) {
      pausedActions.put(action.getTarget(), action);
      if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
                "because tag '" + action.getTag() + "' is paused");
      }
      return;
    }

    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
      hunter.attach(action);
      return;
    }

    if (service.isShutdown()) {
      if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
      }
      return;
    }

    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    hunter.future = service.submit(hunter);
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
      failedActions.remove(action.getTarget());
    }

    if (action.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
  }

BitmapHunter的 forRequest()

static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
      Action action) {
    Request request = action.getRequest();
    List<RequestHandler> requestHandlers = picasso.getRequestHandlers();

    // Index-based loop to avoid allocating an iterator.
    //noinspection ForLoopReplaceableByForEach
    for (int i = 0, count = requestHandlers.size(); i < count; i++) {
      RequestHandler requestHandler = requestHandlers.get(i);
      if (requestHandler.canHandleRequest(request)) {
        return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
      }
    }

    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
  }

基于不一致的加载路线,选拔切合的RequestHandler来制造BitmapHunter

再来看 BitmapHunter 类,实现了 Runnable接口,用来实施网络图片下载、剖判、图形转换等耗费时间操作。

@Override public void run() {
    try {
      updateThreadName(data);

      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
      }

      result = hunt();

      if (result == null) {
        dispatcher.dispatchFailed(this);
      } else {
        dispatcher.dispatchComplete(this);
      }
    } catch (NetworkRequestHandler.ResponseException e) {
      if (!NetworkPolicy.isOfflineOnly(e.networkPolicy) || e.code != 504) {
        exception = e;
      }
      dispatcher.dispatchFailed(this);
    } catch (IOException e) {
      exception = e;
      dispatcher.dispatchRetry(this);
    } catch (OutOfMemoryError e) {
      StringWriter writer = new StringWriter();
      stats.createSnapshot().dump(new PrintWriter(writer));
      exception = new RuntimeException(writer.toString(), e);
      dispatcher.dispatchFailed(this);
    } catch (Exception e) {
      exception = e;
      dispatcher.dispatchFailed(this);
    } finally {
      Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
    }
  }

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

    if (shouldReadFromMemoryCache(memoryPolicy)) {
      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;
      }
    }

    networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    if (result != null) {
      loadedFrom = result.getLoadedFrom();
      exifOrientation = result.getExifOrientation();
      bitmap = result.getBitmap();

      // If there was no Bitmap then we need to decode it from the stream.
      if (bitmap == null) {
        Source source = result.getSource();
        try {
          bitmap = decodeStream(source, data);
        } finally {
          try {
            //noinspection ConstantConditions If bitmap is null then source is guranteed non-null.
            source.close();
          } catch (IOException ignored) {
          }
        }
      }
    }

    if (bitmap != null) {
      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_DECODED, data.logId());
      }
      stats.dispatchBitmapDecoded(bitmap);
      if (data.needsTransformation() || exifOrientation != 0) {
        synchronized (DECODE_LOCK) {
          if (data.needsMatrixTransform() || exifOrientation != 0) {
            bitmap = transformResult(data, bitmap, exifOrientation);
            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;
  }

Bitmap最后是由BitmapHunter的requestHandler.load(卡塔尔(قطر‎方法得到的,Picasso暗中认可提供了ResourceRequestHandler、ContactsPhotoRequestHandler、MediaStoreRequestHandler、ContentStreamRequestHandler、 AssetRequestHandler、FileRequestHandler、NetworkRequestHandler等7中RequestHandler,用来从不一致的根源拿到Bitmap,上边重视深入分析NetworkRequestHandler的兑现。

@Override public Result load(Request request, int networkPolicy) throws IOException {
    okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
    Response response = downloader.load(downloaderRequest);
    ResponseBody body = response.body();

    if (!response.isSuccessful()) {
      body.close();
      throw new ResponseException(response.code(), request.networkPolicy);
    }

    // Cache response is only null when the response comes fully from the network. Both completely
    // cached and conditionally cached responses will have a non-null cache response.
    Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;

    // 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 (loadedFrom == DISK && body.contentLength() == 0) {
      body.close();
      throw new ContentLengthException("Received response with 0 content-length header.");
    }
    if (loadedFrom == NETWORK && body.contentLength() > 0) {
      stats.dispatchDownloadFinished(body.contentLength());
    }
    return new Result(body.source(), loadedFrom);
  }

亨特得到后再通过ExecutorService.submit(State of Qatar 提交到线程池中

成功后dispatcher.dispatchComplete();

void performComplete(BitmapHunter hunter) {
    if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
      cache.set(hunter.getKey(), hunter.getResult());
    }
    hunterMap.remove(hunter.getKey());
    batch(hunter);
    if (hunter.getPicasso().loggingEnabled) {
      log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
    }
  }

最后走到Picasso类中的 complete(卡塔尔国

void complete(BitmapHunter hunter) {
    Action single = hunter.getAction();
    List<Action> joined = hunter.getActions();

    boolean hasMultiple = joined != null && !joined.isEmpty();
    boolean shouldDeliver = single != null || hasMultiple;

    if (!shouldDeliver) {
      return;
    }

    Uri uri = hunter.getData().uri;
    Exception exception = hunter.getException();
    Bitmap result = hunter.getResult();
    LoadedFrom from = hunter.getLoadedFrom();

    if (single != null) {
      deliverAction(result, from, single, exception);
    }

    if (hasMultiple) {
      //noinspection ForLoopReplaceableByForEach
      for (int i = 0, n = joined.size(); i < n; i++) {
        Action join = joined.get(i);
        deliverAction(result, from, join, exception);
      }
    }

    if (listener != null && exception != null) {
      listener.onImageLoadFailed(this, uri, exception);
    }
  }

private void deliverAction(Bitmap result, LoadedFrom from, Action action, Exception e) {
    if (action.isCancelled()) {
      return;
    }
    if (!action.willReplay()) {
      targetToAction.remove(action.getTarget());
    }
    if (result != null) {
      if (from == null) {
        throw new AssertionError("LoadedFrom cannot be null.");
      }
      action.complete(result, from);
      if (loggingEnabled) {
        log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
      }
    } else {
      action.error(e);
      if (loggingEnabled) {
        log(OWNER_MAIN, VERB_ERRORED, action.request.logId(), e.getMessage());
      }
    }
  }

action.complete(卡塔尔国 ,看下完成类ImageViewAction中的 complete(卡塔尔

@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (result == null) {
      throw new AssertionError(
          String.format("Attempted to complete action with no result!n%s", this));
    }

    ImageView target = this.target.get();
    if (target == null) {
      return;
    }

    Context context = picasso.context;
    boolean indicatorsEnabled = picasso.indicatorsEnabled;
    PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);

    if (callback != null) {
      callback.onSuccess();
    }
  }

末段将赢得的bitmap设置到 ImageView 中。

图片加载库

后日小编就Picasso的源码实行解析,抛出有些图片加载的工夫细节供园友参谋。

  public static Picasso with(Context context) {
    if (singleton == null) {
      synchronized (Picasso.class) {
        if (singleton == null) {
          singleton = new Builder(context).build();
        }
      }
    }
    return singleton;
  }

代码方法调用的完整的流程图如下:

澳门新莆京手机网站 3

Picasso方法调用总体流程图.png

Picasso 使用

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

PS:提议园友先大约看一下源码。

此地运用了单例格局,创立了大局唯生龙活虎的Picasso实例

Picasso.with()

Picasso 的入口函数,用于成立全局唯生龙活虎的Picasso 实例,使用 double-check 单例格局

public static Picasso with(Context context) {
if (singleton == null) {
  synchronized (Picasso.class) {
    if (singleton == null) {
      singleton = new Builder(context).build();
    }
  }
}
return singleton;
}

with方法内部通过Builder模式创立Picasso 实例

public Picasso build() {
  Context context = this.context;

  if (downloader == null) {
    downloader = Utils.createDefaultDownloader(context);
  }
  if (cache == null) {
    cache = new LruCache(context);
  }
  if (service == null) {
    service = new PicassoExecutorService();
  }
  if (transformer == null) {
    transformer = RequestTransformer.IDENTITY;
  }

  Stats stats = new Stats(cache);

  Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

  return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
      defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
   }

接受默许的缓存战略,内部存款和储蓄器缓存基于LruCache,磁盘缓存基于http缓存,HttpResponseCache
创建暗中认可的下载器
创办暗许的线程池(3个worker线程State of Qatar
创立暗许的Transformer,这一个Transformer什么事情也不干,只担任转载呼吁
始建私下认可的监察和控制器(StatsState of Qatar,用于计算缓存命中率、下载时间长度等等
始建暗许的Computer集结,即RequestHandlers.它们分别会管理不一致的加载乞请

笔者们对图片加载的渴求

1.加载速度要快

2.能源消耗要低

3.加载图片无法错位

   public Picasso build() {
      Context context = this.context;

      if (downloader == null) {
        //默认下载器
        downloader = Utils.createDefaultDownloader(context);
      }
      if (cache == null) {
        //lru内存缓存
        cache = new LruCache(context);
      }
      if (service == null) {
        //创建线程池,默认3个执行线程
        service = new PicassoExecutorService();
      }
      if (transformer == null) {
       //创建默认的transformer,并无实际作用
        transformer = RequestTransformer.IDENTITY;
      }
      //创建默认的监控器(Stats),用于统计缓存命中率、下载时长等等
      Stats stats = new Stats(cache);
     //创建dispatcher对象用于任务的调度
      Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

      return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
          defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
    }
  }

load(url)

二种重载方法,load(State of Qatar方法用于从分歧地点加载图片,举例互连网、resource、File等,只是创造了三个RequestCreator

public RequestCreator load(...) {

    return new RequestCreator(...);
}

Picasso是还是不是满足须要?

最后三个主意创立了Picasso的实例对象

RequestCreator

RequestCreator是贰个封装供给的类,央求在Picasso中被架空成Request。RequestCreator类提供了 诸如placeholder、tag、error、memoryPolicy、networkPolicy等方法.
Request也运用了Builder形式:

RequestCreator(Picasso picasso, Uri uri, int resourceId)

加载速度要快

1.标配攻略,MemoryCache+DiskCache+Net。进步加载速度,同不常候保障流量。

2.Net局地,两全单央求加载速度与多央求并发技巧,进而抓好总体加载速度。

3.MemoryCache部分,通过Lru计策进步缓存功效。

那之中根本做关于部分赋值操作,以至开创一些新的目的,比如清理线程等等.最要害的是发轫化了requestHandlers,如下

RequestCreator.into()

into方法有多样重载,Picasso不只有可以将图片加载到ImageView上,仍可以够加载Target可能RemoteView上.

public void into(Target target) {
long started = System.nanoTime();
//检查是否在主线程运行
checkMain();

if (target == null) {
  throw new IllegalArgumentException("Target must not be null.");
}
if (deferred) {
  throw new IllegalStateException("Fit cannot be used with a Target.");
}

if (!data.hasImage()) {
  picasso.cancelRequest(target);
  target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
  return;
}
//创建request
Request request = createRequest(started);
String requestKey = createKey(request);

if (shouldReadFromMemoryCache(memoryPolicy)) {//是否需要在缓存里面先查找
  Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);//使用请求生成的key查找缓存
  if (bitmap != null) {
    picasso.cancelRequest(target);
    target.onBitmapLoaded(bitmap, MEMORY);
    return;
  }
}

target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);

// 将request封装成action
Action action =
    new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
        requestKey, tag, errorResId);
// 提交action
picasso.enqueueAndSubmit(action);
}

Request
关爱的是央浼小编,比方央求的源、id、初步时间、图片转变配置、优先级等等,而Action则象征的是三个加载职务,所以不唯有必要Request对象的引用,还需求Picasso实例,是不是重试加载等等
Action
有个须要关心的点,那正是WeakReference<T> target,它具备的是Target(比方ImageView..卡塔尔的弱援引,那样能够确定保证加载时间十分长的动静下 也不会潜濡默化到Target的回笼了.

void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
if (target != null && targetToAction.get(target) != action) {
  // This will also check we are on the main thread.
  cancelExistingRequest(target);
  targetToAction.put(target, action);
}
submit(action);
}

void submit(Action action) {
dispatcher.dispatchSubmit(action);
}

enqueueAndSubmit 它会先从action职分上获得对应target,也等于imageView,然后从weakHashMap中通过这一个imageView索引到对应的action,借使开掘这一个action跟传进来的action区别等的话,那就废除掉早先的加载职务。最终将日前加载职务提交.

末段调用的是Dispatcher的dispatchSubmit(action卡塔尔国方法.
Dispatcher即职责分发器,它是在 Picasso实例创造的时候起始化的.。

财富消耗要低

1.渲染适当尺寸图片来压缩内部存储器。

2.通过线程池来界定并发的图样加载线程,减弱能源消耗。

3.诉求相像图片的线程要统生龙活虎,减弱线程数。

 List<RequestHandler> allRequestHandlers =
        new ArrayList<RequestHandler>(builtInHandlers + extraCount);

    // ResourceRequestHandler needs to be the first in the list to avoid
    // forcing other RequestHandlers to perform null checks on request.uri
    // to cover the (request.resourceId != 0) case.
    allRequestHandlers.add(new ResourceRequestHandler(context));
    if (extraRequestHandlers != null) {
      allRequestHandlers.addAll(extraRequestHandlers);
    }
    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));
    requestHandlers = Collections.unmodifiableList(allRequestHandlers);

Dispatcher

Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

每一个Dispatcher都亟需关联线程池(service卡塔尔国、下载器(downloader卡塔尔(قطر‎、主线程的Handler(HANDLETucson卡塔尔(قطر‎、缓存(cacheState of Qatar、 监察和控制器(stats卡塔尔(قطر‎.

加载图片不可能错位

AdapterView会 复用 View,Picasso通过Map<ImageView,Action>机制确认保障View彰显正确的图。

可以知道,Picasso已经满足了大家对图纸加载的急需。

接下去正是调用load(卡塔尔国方法传入String,Uri可能File对象了

PicassoExecutorService

private static final int DEFAULT_THREAD_COUNT = 3;

PicassoExecutorService() {
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
    new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
}

暗中同意线程数量为 3.可是PicassoExecutorService的特色是足以依据网络状态调解线程数量,wifi下是4个线程,而2g网独有五个线程。具体是 通过在Dispatcher中登记了监听互联网转移的播放接受者。

Picasso的有的为主方针

这里的load(卡塔尔国方法均是开创了RequestCreator对象,如下

DispatcherThread 是 Dispatcher 的当中类

static class DispatcherThread extends HandlerThread

切换成子线程

void performSubmit(Action action, boolean dismissFailed) {
if (pausedTags.contains(action.getTag())) {
  pausedActions.put(action.getTarget(), action);
  if (action.getPicasso().loggingEnabled) {
    log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
        "because tag '" + action.getTag() + "' is paused");
  }
  return;
}

BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
  hunter.attach(action);
  return;
}

if (service.isShutdown()) {
  if (action.getPicasso().loggingEnabled) {
    log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
  }
  return;
}

hunter = forRequest(action.getPicasso(), this, cache, stats, action);
hunter.future = service.submit(hunter);
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
  failedActions.remove(action.getTarget());
}

if (action.getPicasso().loggingEnabled) {
  log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}

始建了三个BitmapHunter完成Runnable接口,能够被线程池调用。然后判别线程池有未有关闭,若无的话, 就能够将以此bitmapHunter submit线程池里面

上一篇:澳门新莆京手机网站app运转时间测验 下一篇:没有了

Copyright © 2015-2019 http://www.carrefourstation.com. 澳门新莆京手机网站-新蒲京娱乐场有限公司 版权所有