Picasso
一、例子
直接上代碼
如下就是Picasso最簡單的例子,我們在使用的時候就是這么簡單,直接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);
二、原理
首先來看三個函數,第一個是with函數,很顯然使用的是單例模式和Builder模式,然后創建一個Picasso的實例
public static Picasso with(Context context) {if (singleton == null) {synchronized (Picasso.class) {if (singleton == null) {singleton = new Builder(context).build();}}}return singleton;}
然后load函數,這個有好幾個,分別針對的是不同的資源類型
public RequestCreator load(Uri uri) {... } public RequestCreator load(String path) {... } public RequestCreator load(int resourceId) {... }
最后是into函數,這個函數還是比較復雜的一個函數
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); }這里最主要的就是創建一個Reques對象,我們前面做的一些封裝和設置都會封裝到這個Request對象中
檢查我們要顯示的圖片是否可以直接在緩存中獲取,如果有就直接顯示出來好了。
緩存沒命中,那就只能費點事把源圖片down下來了。這個過程是異步的,并且通過一個Action來完成請求前后的銜接工作。
首先進行參數的設置,然后創建request請求對象,最后通過通過action來進行圖片的請求。
1. 首先看一下構造函數
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {... }我們是通過單例和建造者模式來完成實例化的,在build的過程中向picasso中傳遞這些參數,自己來靈活的定制
2、看一build函數中的代碼是什么樣子
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:它是一個接口,規定了一些通用的方法,這也就意味著,我們可以提供自己的下載器
Cache:Picasso的緩存,這里實例化的是LruCache,其內部使用的是LinkedHashMap
ExecutorService:這里Picasso實現了自己的PicassoExecutorService,它繼承了ThreadPoolExecutor,也就是Picasso自己維護了一個線程池,用于異步加載圖片。
Stats:這個類只要是維護圖片的一些狀態Dispatcher:從名字上就可以判斷出來,這個類在這里起到了一個調度器的作用,圖片要不要開始下載以及下載后Bitmap的返回都是通過這個調度器來執行的
3、也是通過異步請求的方式來進行的
上面的into方法中中最終會創建一個action,這個action里邊包含picasso對象、目標和Request請求等
然后會調用enqueueAndSubmit方法,而最終是調用了Dispatcher的dispatchSubmit方法,也就是我們前面說的,Dispatcher起到了調度器的作用。在Dispatcher內部,Dispatcher定義了DispatcherThread和DispatcherHandler兩個內部類,并在Dispatcher的構造函數中對他們經行了實例化,所有的調度也都是通過handler異步的執行的,如下是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);... }構建實例之后建立一個 BitmapHunter類來進行圖片的加載,這個類也是繼承Runnable接口的類,加載完成圖片之后怎么去進行進行主線程的更新是個問題
4、進行圖片的主線程跟新操作
因為是異步的,最終也是通過消息機制來進行發送的,同message的方式發送到主線程中進行圖片的渲染和更新的操作
Picasso并不是立即將圖片顯示出來,而是用到了一個批處理,其實就是把操作先暫存在一個list中,等空閑的時候再拿出來處理,這樣做得好處也是盡量減少主線程的執行時間,一方面防止ANR,另一方面快速返回,響應頁面的其他渲染操作,防止卡頓用戶界面。
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);} }
尊重作者,尊重原創,參考文章:
http://www.jianshu.com/p/459c8ca3f337
總結
- 上一篇: 计算机考研跨考新闻学,研友自述:跨专业考
- 下一篇: 单片机毕业设计 Stm32智能防控门禁系