picasso框架

picasso 是一個(gè)強(qiáng)大的圖片加載緩存框架

1.首先看下picasso 如何使用:

Picasso.with(this)
.load("url")
.placeholder(R.drawable.leak_canary_icon)
.error(R.drawable.leak_canary_icon)
.resize(480,800)
.centerCrop()
.rotate(360)
.priority(Picasso.Priority.HIGH)
.tag("picasso listview")
.memoryPolicy(MemoryPolicy.NO_CACHE)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(imageView);

Picasso和Glide相似都是使用鏈?zhǔn)秸{(diào)用 我們可以把Picasso類視為一個(gè)管理類,管理圖片的加載,轉(zhuǎn)換,緩存的工作.
.with()獲取Picasso的單例,參數(shù)是上下文.
.load()方法完成加載圖片的方法.參數(shù)是url或file路徑
.resize()方法 參數(shù)單位像素 因?yàn)樵陧?xiàng)目中要考慮網(wǎng)絡(luò)帶寬,手機(jī)的內(nèi)存使用,下載速度等情況.結(jié)合考慮.這時(shí)候有一種場景服務(wù)器給我們的圖片的寬和高與我們實(shí)際的imageview的寬和高是不一致的.服務(wù)器給我們一些奇奇怪怪的圖片,這時(shí)我們就要調(diào)用resize方法.對圖片的寬高進(jìn)行設(shè)置.
.centerCrop() 將整個(gè)圖片充滿imageview邊界 裁減掉多余部分
.rotate() 對圖片加載進(jìn)行旋轉(zhuǎn)設(shè)置.旋轉(zhuǎn)點(diǎn)坐標(biāo)0.0
.priority(Picasso.Priority.HIGH) 設(shè)置圖片加載優(yōu)先級 不是100%保證 因?yàn)閜icasso內(nèi)部只是向高的優(yōu)先級靠攏.但并不會保證
.tag() Picasso 允許我們?yōu)槊總€(gè)請求設(shè)置一個(gè)tag 為什么用到tag呢 比如listview 快速滑動這樣的場景,如果不去設(shè)置響應(yīng)事件就會加載所有的圖片,浪費(fèi)性能,造成體驗(yàn)不好.UI卡頓,而我們?yōu)槊恳粋€(gè)加載事件做標(biāo)記tag,監(jiān)聽響應(yīng)事件.做出處理操作.

mlsitview.setOnScrollStateChanged(AbsListView view,int scrollState){
final Picasso picasso = Picasso.with(MainActivity.this);
if(scrollState == SCROLL_STATE_IDLE){//停止?fàn)顟B(tài)加載圖片
picasso.resumeTag("picasso listview");
}else{
picasso.pauseTag("picasso listview");
}
}

.memoryPolicy(MemoryPolicy.NO_CACHE) picasso的緩存策略 內(nèi)存緩存
.networkPolicy(NetworkPolicy.NO_CACHE)文件緩存

2.picasso源碼分析

1)with方法:內(nèi)存緩存Lrucache和線程池調(diào)度

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

.build()方法,生成Picasso對象,返回該對象實(shí)例,按照需求配置下載器,緩存,線程池,轉(zhuǎn)換器等.

 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;//轉(zhuǎn)換器
      }

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

.build()方法.-->downloader = Utils.createDefaultDownloader(context);
-->

static Downloader createDefaultDownloader(Context context) {
    try {
      Class.forName("com.squareup.okhttp.OkHttpClient");//通過反射查找是否引用了okhttp,如果引用了采用okhttp進(jìn)行網(wǎng)絡(luò)連接
      return OkHttpLoaderCreator.create(context);
    } catch (ClassNotFoundException ignored) {
    }
    return new UrlConnectionDownloader(context);//沒有引用,采用httpurlConnection進(jìn)行網(wǎng)絡(luò)請求
  }

繼續(xù)看build方法中

 if (cache == null) {
        cache = new LruCache(context);//lruCache主要采用linkedhashmap 將圖片添加到鏈表尾部//( final LinkedHashMap<String, Bitmap> map;)
      }
      if (service == null) {
        service = new PicassoExecutorService();
      }

接著來看PicassoExecutorService
PicassoExecutorService 是一個(gè)線程并發(fā)池
PicassoExecutorService extends ThreadPoolExecutor
ThreadPoolExecutor是java并發(fā)庫中的內(nèi)容 無論是圖片庫還是網(wǎng)絡(luò)庫都離不開這個(gè)線程池

public ThreadPoolExecutor(int corePoolSize, //核心線程數(shù)目
                              int maximumPoolSize,//線程池中允許的最大線程數(shù)
                              long keepAliveTime,//線程池中線程數(shù)目比核心線程數(shù)目多的時(shí)候,超過這個(gè)時(shí)間,就會將多余的線程回收
                              TimeUnit unit,//時(shí)間單位
                              BlockingQueue<Runnable> workQueue,//阻塞隊(duì)列 線程安全隊(duì)列
                              ThreadFactory threadFactory,//線程工廠 產(chǎn)生線程
                              RejectedExecutionHandler handler) {}//當(dāng)線程池 由于線程數(shù)目和隊(duì)列導(dǎo)致任務(wù)阻塞時(shí) ,線程池的處理方式

1.如果線程池中的線程數(shù)目少于corePoolSize , 這時(shí)候線程池是會重新創(chuàng)建線程的,直到線程數(shù)目達(dá)到corePoolSize.
2.如果線程池中線程數(shù)目大于或者等于corePoolSize,但是工作隊(duì)列workQueue沒有滿, 這時(shí)新的任務(wù)還是會放進(jìn)隊(duì)列中的,按照先進(jìn)先出的原則來進(jìn)行執(zhí)行.
3.如果線程池中的線程數(shù)目大于等于corePoolSize,并且工作隊(duì)列workQueue滿了,但是總線程數(shù)目小于maximumPoolSzie 這時(shí)候還是可以直接創(chuàng)建線程 來處理添加的任務(wù)
4.如果工作隊(duì)列滿了,并且線程池中線程的數(shù)目達(dá)到了最大數(shù)目maximumPoolSize 這時(shí)就會由RejectedExecutionHandler來處理
默認(rèn)的處理方式就是 丟棄到任務(wù),同時(shí)拋出異常
繼續(xù)看
非常重要的 Dispatcher 是來管理非常重要的線程之間的切換.
dispatcher如何完成線程切換
首先我們進(jìn)入Dispatcher這個(gè)類,Dispatcher類中首先開啟線程DispatcherThread

final DispatcherThread dispatcherThread;
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start();

首先DispatcherThread extends HandlerThread

static class DispatcherThread extends HandlerThread {
    DispatcherThread() {
      super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
    }
  }

所以先分析下HandlerThread
HandlerThread extends Thread 注釋中這樣寫到他會開啟一個(gè)新的線程,線程內(nèi)部會有一個(gè)Looper對象,通過這個(gè)Looper對象可以去循環(huán)遍歷我們的消息隊(duì)列.
看下run()方法
run方法的作用就是完成Looper的創(chuàng)建 通過Looper的循環(huán)方法構(gòu)造一個(gè)循環(huán)的線程.HandlerThread也要調(diào)用start方法,完成線程的運(yùn)行的.

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//完成Looper對象的創(chuàng)建
        synchronized (this) {//通過同步鎖機(jī)制鎖住當(dāng)前對象
            mLooper = Looper.myLooper();//mLooper在我們的同步代碼塊中
            notifyAll();//喚醒等待線程 和notifyAll()同步出現(xiàn)的就是wait()方法.
        }
        Process.setThreadPriority(mPriority);//設(shè)置線程優(yōu)先級
        onLooperPrepared();//內(nèi)部是個(gè)空實(shí)現(xiàn) 留給我們自己去重寫
        Looper.loop();//完成整個(gè)的線程消息啟動工作
        mTid = -1;
    }

//我們回到同步代碼塊中 我們?yōu)槭裁匆ㄟ^同步代碼塊中的方法去喚醒等待線程呢?有在哪里去wait的操作呢?
在getLooper方法中

 public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {//這里同樣用同步鎖機(jī)制鎖住當(dāng)前對象
            while (isAlive() && mLooper == null) {//判斷線程存貨且不為空的情況下
                try {
                    wait();//線程等待
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

繼續(xù)看Dispatcher構(gòu)造方法中的其他參數(shù)

Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
      Downloader downloader, Cache cache, Stats stats) {
    this.dispatcherThread = new DispatcherThread();
    this.dispatcherThread.start();
    Utils.flushStackLocalLeaks(dispatcherThread.getLooper());
    this.context = context;
    this.service = service;
    this.hunterMap = new LinkedHashMap<String, BitmapHunter>();
    this.failedActions = new WeakHashMap<Object, Action>();
    this.pausedActions = new WeakHashMap<Object, Action>();
    this.pausedTags = new HashSet<Object>();
    this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);//dispatherThread線程內(nèi)部的handler(因?yàn)閐ispatcherThread.getLooper()參數(shù))
    this.downloader = downloader;
    this.mainThreadHandler = mainThreadHandler;//主線程的handler
    this.cache = cache;
    this.stats = stats;
    this.batch = new ArrayList<BitmapHunter>(4);
    this.airplaneMode = Utils.isAirplaneModeOn(this.context);
    this.scansNetworkChanges = hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
    this.receiver = new NetworkBroadcastReceiver(this);//廣播接收者,主要用于監(jiān)聽網(wǎng)絡(luò)變化的操作的,這也是比較重要的
    receiver.register();
  }

回到picasso的build()方法中
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
HANDLER是picasso內(nèi)部定義的
static final Handler HANDLER = new Handler(Looper.getMainLooper()){//getMainLooper是主線程
}//定義為靜態(tài)內(nèi)部類,就是靜態(tài)內(nèi)部類不持有外部類的引用

3.NetworkRequestHandler處理圖片請求與回調(diào)

繼續(xù)看build()方法
build()方法最后 還是返回一個(gè)picasso對象
return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
我們進(jìn)入這個(gè)方法看一下

  Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
      RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
      Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
  this.context = context;
    this.dispatcher = dispatcher;
    this.cache = cache;
    this.listener = listener;
    this.requestTransformer = requestTransformer;
    this.defaultBitmapConfig = defaultBitmapConfig;

    int builtInHandlers = 7; // Adjust this as internal handlers are added or removed.
    int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
    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);//將extraRequestHandlers集合加入到allRequesthandlers集合中,看下
allRequestHandler這個(gè)ArrayList集合.

    }
    allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
    allRequestHandlers.add(new MediaStoreRequestHandler(context));
    allRequestHandlers.add(new ContentStreamRequestHandler(context));//集合中加入處理contentprovider中圖片的handler
    allRequestHandlers.add(new AssetRequestHandler(context));//處理asset中圖片
    allRequestHandlers.add(new FileRequestHandler(context));//處理file中圖片
    allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));//處理網(wǎng)絡(luò)請求圖片的handler
    requestHandlers = Collections.unmodifiableList(allRequestHandlers);

    this.stats = stats;
    this.targetToAction = new WeakHashMap<Object, Action>();
    this.targetToDeferredRequestCreator = new WeakHashMap<ImageView, DeferredRequestCreator>();
    this.indicatorsEnabled = indicatorsEnabled;
    this.loggingEnabled = loggingEnabled;
    this.referenceQueue = new ReferenceQueue<Object>();
    this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
    this.cleanupThread.start();
}

我們主要看下處理網(wǎng)絡(luò)請求圖片的handler:NetworkRequestHandler.主要看其中的load()方法:

@Override public Result load(Request request, int networkPolicy) throws IOException {
    Response response = downloader.load(request.uri, request.networkPolicy);
    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 (loadedFrom == DISK && response.getContentLength() == 0) {
      Utils.closeQuietly(is);
      throw new ContentLengthException("Received response with 0 content-length header.");
    }
    if (loadedFrom == NETWORK && response.getContentLength() > 0) {//請求響應(yīng)長度>0
      stats.dispatchDownloadFinished(response.getContentLength());//stats派發(fā)響應(yīng)完成結(jié)果
    }
    return new Result(is, loadedFrom);
  }

看下stats的dispatchDownloadFinished方法:

void dispatchDownloadFinished(long size) {
    handler.sendMessage(handler.obtainMessage(DOWNLOAD_FINISHED, size));
  }

發(fā)現(xiàn)了熟悉的sendMessage()方法
其中的handler是StatsHandler 看其中handleMessage()方法:

 @Override public void handleMessage(final Message msg) {
      switch (msg.what) {
        case CACHE_HIT:
          stats.performCacheHit();
          break;
        case CACHE_MISS:
          stats.performCacheMiss();
          break;
        case BITMAP_DECODE_FINISHED:
          stats.performBitmapDecoded(msg.arg1);
          break;
        case BITMAP_TRANSFORMED_FINISHED:
          stats.performBitmapTransformed(msg.arg1);
          break;
        case DOWNLOAD_FINISHED:
          stats.performDownloadFinished((Long) msg.obj);

          break;
        default:
          Picasso.HANDLER.post(new Runnable() {
            @Override public void run() {
              throw new AssertionError("Unhandled stats message." + msg.what);
            }
          });
      }
    }

Stats中的performDownloadFinished()方法

  void performDownloadFinished(Long size) {
    downloadCount++;
    totalDownloadSize += size;
    averageDownloadSize = getAverage(downloadCount, totalDownloadSize);
  }

4.picasso源碼load方法

load 方法return load(Uri.parse(path)).
該函數(shù)有四種重載方法,其中Uri江场,String垂谢,F(xiàn)ile最終都轉(zhuǎn)化為Uri進(jìn)行請求片效,而int則是app內(nèi)部的資源訪問尽楔。
load()函數(shù)返回RequestCreator對象繁涂,

 public RequestCreator load(Uri uri) {
    return new RequestCreator(this, uri, 0);
  }

再看RequestCreator();
RequestCreator的成員變量里有一個(gè)重要的對象是Request.Builder(其有一個(gè)內(nèi)部類Builder)盹靴,RequestCreator里很多函數(shù)都是橋 接到該Builder炸茧。

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

看最后一行是創(chuàng)建了 Request.Builder對象,通過Request.Builder對象我們可以配置更多對象.

picasso源碼into方法:Action&BitmapHunter

with()方法完成了Picasso對象的創(chuàng)建,內(nèi)部通過單例的形式進(jìn)行構(gòu)建,這樣就保證了在app使用Picasso對象的時(shí)候,只會存在一個(gè)
picasso對象,同時(shí)他也是我們整個(gè)Picasso加載的入口.同時(shí)with()方法還做了一些基礎(chǔ)的配置工作.比如說Dispatcher這個(gè)類,在picasso框架中主要完成線程的切換工作,其內(nèi)部實(shí)現(xiàn)原理是handler.
load()方法主要完成了RequsetCreate()方法的創(chuàng)建.同時(shí)獲取到了我們要加載的一些資源的路徑
into()方法完成圖片的加載工作.

DeferredRequestCreator類
當(dāng)我們創(chuàng)建請求的時(shí)候,我們新建一個(gè)圖片加載請求,但是我們還不能獲取到當(dāng)imageview的寬高,這時(shí)我們會創(chuàng)建DeferredRequestCreator,通過這個(gè)類會我們的imageview的target去進(jìn)行監(jiān)聽,直到獲取到當(dāng)前imageview的寬高,這時(shí)候我們重新執(zhí)行我們的請求創(chuàng)建.所以刪除請求的時(shí)候,同時(shí)我們還應(yīng)該刪除DeferredRequestCreator對target的監(jiān)聽事件.

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.");
    }
//沒設(shè)置url以及resId則取消請求
    if (!data.hasImage()) {
      picasso.cancelRequest(target);//取消請求
      target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);//取消后設(shè)置占位符.
      return;
    }

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

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

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

    Action action =
        new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
            requestKey, tag, errorResId);
//提交請求,Picasso內(nèi)部維護(hù)了一個(gè)map稿静,key是imageView梭冠,value是Action
//提交時(shí)做判斷,如果當(dāng)前imageView已經(jīng)在任務(wù)隊(duì)列里了改备。判斷當(dāng)前任務(wù)與之前的任務(wù)是否相同控漠,
//如果不相同則取消之前的任務(wù)并將新的key-value加入到map
    picasso.enqueueAndSubmit(action);
}

RequestCreator最重要的一個(gè)方法是into(),在into()方法調(diào)用之前所調(diào)用的一切配置函數(shù)都只是把配置信息儲 存起來绍妨,而沒有做網(wǎng)絡(luò)請求润脸,當(dāng)調(diào)用into()函數(shù)后才開始網(wǎng)絡(luò)請求。into()函數(shù)有五個(gè)重載方法他去,用于把請求結(jié)果存 放或顯示到指定位置毙驯。

submit()函數(shù):用于把RequestCreator提交上來的Action添加到隊(duì)列里,該函數(shù)其實(shí)是把提交任務(wù)交給Dispatcher

image

而Dispatcher最后則通過handler把任務(wù)切換到Dispatcher所在的線程(后臺線程灾测,因?yàn)橐M(jìn)行網(wǎng)絡(luò)訪問).

RequestCreator最重要的一個(gè)方法是into()爆价,在into()方法調(diào)用之前所調(diào)用的一切配置函數(shù)都只是把配置信息儲 存起來垦巴,而沒有做網(wǎng)絡(luò)請求,當(dāng)調(diào)用into()函數(shù)后才開始網(wǎng)絡(luò)請求铭段。into()函數(shù)有五個(gè)重載方法骤宣,用于把請求結(jié)果存 放或顯示到指定位置。

image

這里分析into到ImageView里序愚,該函數(shù)首先會查看緩存里是否有請求的Bitmap憔披,如果有那最好,都不用進(jìn)行網(wǎng)絡(luò)請求爸吮, 直接把Bitmap顯示到ImageView里芬膝。如果緩存里沒有,則會把請求加入到請求隊(duì)列里形娇,之后進(jìn)行網(wǎng)絡(luò)請求锰霜。

到這里,又把控制權(quán)交給Picasso類桐早。

image

底層分析:
Action 類:是一個(gè)request請求類包裝類,最終把包裝好的類,交給線程還執(zhí)行.(一個(gè)沒有Set的Bean癣缅,包含各種動作信息,如網(wǎng)絡(luò)請求策略哄酝,內(nèi)存策略友存,請求配置等。)
BitmapHuntyer 就是一個(gè)runnable,是一個(gè)開啟子線程的工具.是一個(gè)Runnable的子類陶衅,用來進(jìn)行Bitmap的獲取(網(wǎng)絡(luò)爬立,硬盤,內(nèi)存等)万哪,處理(角度,大小等)抡秆,然后執(zhí)行分發(fā)器(dispatcher)的回調(diào)處理

picasso源碼into方法:線程池&PicassoFutureTask

Stats:對請求整個(gè)過程的一個(gè)記錄奕巍,如命中(hit)緩存的次數(shù),不命中(miss)緩存的次數(shù)儒士,Bitmap下載解析次數(shù)的止, 下載完成次數(shù)等。
ImageViewAction:Action的子類着撩,內(nèi)部有complete()和error()函數(shù)诅福,用于把請求結(jié)果顯示到ImageView上
其實(shí)Picasso里用來在指定目標(biāo)上顯示結(jié)果都是通過PicassoDrawable類來實(shí)現(xiàn)的。

再次 強(qiáng)調(diào)下最重要的類

RequestHandler

//抽象類拖叙,由不同的子類來實(shí)現(xiàn)不同來源的圖片的獲取與加載氓润,比如:
//AssetRequestHandler:加載asset里的圖片
//FileRequestHandler:加載硬盤里的圖片
//ResourceRequestHandler:加載資源圖片
//NetworkRequestHandler:加載網(wǎng)絡(luò)圖片

BitmapHunter

//是一個(gè)Runnable的子類,用來進(jìn)行Bitmap的獲取(網(wǎng)絡(luò)薯鳍,硬盤咖气,內(nèi)存等),處理(角度,大小等)崩溪,
//然后執(zhí)行分發(fā)器(dispatcher)的回調(diào)處理

PicassoDrawable

//實(shí)現(xiàn)了引入圖片漸變功能和debug狀態(tài)的標(biāo)識的Drawable浅役,用來在最后bitmap轉(zhuǎn)換成PicassoDrawable
//然后設(shè)置給ImageView,根據(jù)圖片的來源可以在圖片的左上角顯示一個(gè)不同顏色的三角形色塊
MEMORY(Color.GREEN) //內(nèi)存加載
DISK(Color.BLUE) //本地加載
NETWORK(Color.RED) //網(wǎng)絡(luò)加載

DeferredRequestCreator

//ViewTreeObserver.OnPreDrawListener的實(shí)現(xiàn)類伶唯,即將繪制視圖樹時(shí)執(zhí)行的回調(diào)函數(shù)觉既。
//這時(shí)所有的視圖都測量完成并確定了框架。 客戶端可以使用該方法來調(diào)整滾動邊框乳幸,
//甚至可以在繪制之前請求新的布局瞪讼,這里用來實(shí)現(xiàn)當(dāng)開發(fā)者修改圖片尺寸時(shí)的邏輯

Action

//Action代表了一個(gè)具體的加載任務(wù),主要用于圖片加載后的結(jié)果回調(diào)反惕,有兩個(gè)抽象方法尝艘,complete和error,
//并保存了每個(gè)請求的各種信息()姿染,具體的實(shí)現(xiàn)類如下
//GetAction:同步執(zhí)行請求時(shí)使用背亥。
//FetchAction:當(dāng)不需要ImageView來安置bitmap時(shí)的異步請求,通常用來預(yù)熱緩存
//RemoteViewsAction:用來更新遠(yuǎn)程圖片(notification等)的抽象類悬赏。
//TargetAction:一般在View(不只是ImageView)或者ViewHolder中用來加載圖片,需要實(shí)現(xiàn)Target接口
//ImageViewAction:最常用的Action狡汉,主要用來給ImageView加載圖片

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市闽颇,隨后出現(xiàn)的幾起案子盾戴,更是在濱河造成了極大的恐慌,老刑警劉巖兵多,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尖啡,死亡現(xiàn)場離奇詭異,居然都是意外死亡剩膘,警方通過查閱死者的電腦和手機(jī)衅斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怠褐,“玉大人畏梆,你說我怎么就攤上這事∧卫粒” “怎么了奠涌?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磷杏。 經(jīng)常有香客問我溜畅,道長,這世上最難降的妖魔是什么极祸? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任辜昵,我火速辦了婚禮,結(jié)果婚禮上瓦阐,老公的妹妹穿的比我還像新娘伴鳖。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般物邑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滔金,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天色解,我揣著相機(jī)與錄音,去河邊找鬼餐茵。 笑死科阎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的忿族。 我是一名探鬼主播锣笨,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼道批!你這毒婦竟也來了错英?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤隆豹,失蹤者是張志新(化名)和其女友劉穎椭岩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體璃赡,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡判哥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碉考。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姨伟。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖豆励,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞒渠,我是刑警寧澤良蒸,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站伍玖,受9級特大地震影響嫩痰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窍箍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一串纺、第九天 我趴在偏房一處隱蔽的房頂上張望丽旅。 院中可真熱鬧,春花似錦纺棺、人聲如沸榄笙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅撞。三九已至,卻和暖如春巨朦,著一層夾襖步出監(jiān)牢的瞬間米丘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工糊啡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拄查,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓棚蓄,卻偏偏與公主長得像堕扶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子癣疟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容