Picasso
一、例子
直接上代碼
如下就是Picasso最簡(jiǎn)單的例子,我們?cè)谑褂玫臅r(shí)候就是這么簡(jiǎn)單,直接with、load、into
// 普通加載圖片Picasso.with(PicassoActivity.this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg").into(ivPicassoResult1);// 裁剪的方式加載圖片Picasso.with(PicassoActivity.this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg").resize(100,100).into(ivPicassoResult2);// 選擇180度Picasso.with(PicassoActivity.this).load("http://n.sinaimg.cn/translate/20160819/9BpA-fxvcsrn8627957.jpg").rotate(180).into(ivPicassoResult3);
二、原理
首先來看三個(gè)函數(shù),第一個(gè)是with函數(shù),很顯然使用的是單例模式和Builder模式,然后創(chuàng)建一個(gè)Picasso的實(shí)例
public static Picasso with(Context context) {if (singleton == null) {synchronized (Picasso.class) {if (singleton == null) {singleton = new Builder(context).build();}}}return singleton;}
然后load函數(shù),這個(gè)有好幾個(gè),分別針對(duì)的是不同的資源類型
public RequestCreator load(Uri uri) {... } public RequestCreator load(String path) {... } public RequestCreator load(int resourceId) {... }
最后是into函數(shù),這個(gè)函數(shù)還是比較復(fù)雜的一個(gè)函數(shù)
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 = 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.enqueueAndSubmit(action); }這里最主要的就是創(chuàng)建一個(gè)Reques對(duì)象,我們前面做的一些封裝和設(shè)置都會(huì)封裝到這個(gè)Request對(duì)象中
檢查我們要顯示的圖片是否可以直接在緩存中獲取,如果有就直接顯示出來好了。
緩存沒命中,那就只能費(fèi)點(diǎn)事把源圖片down下來了。這個(gè)過程是異步的,并且通過一個(gè)Action來完成請(qǐng)求前后的銜接工作。
首先進(jìn)行參數(shù)的設(shè)置,然后創(chuàng)建request請(qǐng)求對(duì)象,最后通過通過action來進(jìn)行圖片的請(qǐng)求。
1. 首先看一下構(gòu)造函數(shù)
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {... }我們是通過單例和建造者模式來完成實(shí)例化的,在build的過程中向picasso中傳遞這些參數(shù),自己來靈活的定制
2、看一build函數(shù)中的代碼是什么樣子
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); }
Downloader:它是一個(gè)接口,規(guī)定了一些通用的方法,這也就意味著,我們可以提供自己的下載器
Cache:Picasso的緩存,這里實(shí)例化的是LruCache,其內(nèi)部使用的是LinkedHashMap
ExecutorService:這里Picasso實(shí)現(xiàn)了自己的PicassoExecutorService,它繼承了ThreadPoolExecutor,也就是Picasso自己維護(hù)了一個(gè)線程池,用于異步加載圖片。
Stats:這個(gè)類只要是維護(hù)圖片的一些狀態(tài)Dispatcher:從名字上就可以判斷出來,這個(gè)類在這里起到了一個(gè)調(diào)度器的作用,圖片要不要開始下載以及下載后Bitmap的返回都是通過這個(gè)調(diào)度器來執(zhí)行的
3、也是通過異步請(qǐng)求的方式來進(jìn)行的
上面的into方法中中最終會(huì)創(chuàng)建一個(gè)action,這個(gè)action里邊包含picasso對(duì)象、目標(biāo)和Request請(qǐng)求等
然后會(huì)調(diào)用enqueueAndSubmit方法,而最終是調(diào)用了Dispatcher的dispatchSubmit方法,也就是我們前面說的,Dispatcher起到了調(diào)度器的作用。在Dispatcher內(nèi)部,Dispatcher定義了DispatcherThread和DispatcherHandler兩個(gè)內(nèi)部類,并在Dispatcher的構(gòu)造函數(shù)中對(duì)他們經(jīng)行了實(shí)例化,所有的調(diào)度也都是通過handler異步的執(zhí)行的,如下是Dispatcher
Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,Downloader downloader, Cache cache, Stats stats) {this.dispatcherThread = new DispatcherThread();this.dispatcherThread.start();...this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);... }構(gòu)建實(shí)例之后建立一個(gè) BitmapHunter類來進(jìn)行圖片的加載,這個(gè)類也是繼承Runnable接口的類,加載完成圖片之后怎么去進(jìn)行進(jìn)行主線程的更新是個(gè)問題
4、進(jìn)行圖片的主線程跟新操作
因?yàn)槭钱惒降?#xff0c;最終也是通過消息機(jī)制來進(jìn)行發(fā)送的,同message的方式發(fā)送到主線程中進(jìn)行圖片的渲染和更新的操作
Picasso并不是立即將圖片顯示出來,而是用到了一個(gè)批處理,其實(shí)就是把操作先暫存在一個(gè)list中,等空閑的時(shí)候再拿出來處理,這樣做得好處也是盡量減少主線程的執(zhí)行時(shí)間,一方面防止ANR,另一方面快速返回,響應(yīng)頁面的其他渲染操作,防止卡頓用戶界面。
private void batch(BitmapHunter hunter) {if (hunter.isCancelled()) {return;}batch.add(hunter);if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);} }
尊重作者,尊重原創(chuàng),參考文章:
http://www.jianshu.com/p/459c8ca3f337
總結(jié)
- 上一篇: 计算机考研跨考新闻学,研友自述:跨专业考
- 下一篇: 新一代“独角兽”,上汽集团网约车获10亿