1. 程式人生 > >Android圖片載入框架Picasso使用教程 (三)

Android圖片載入框架Picasso使用教程 (三)

前面我們對Picasso的用法有了一定得了解,下面就分析一下一些特殊情況下,Picasso的用法.

呼叫.noFade()

  Picasso的預設圖片載入方式有一個淡入的效果,如果呼叫了noFade(),載入的圖片將直接顯示在ImageView上


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .placeholder(R.mipmap.ic_launcher)  
  5.     .error(R.mipmap.future_studio_launcher)  
  6.     .noFade()
  7.     .into(imageViewFade);</font>
複製程式碼
呼叫.noPlaceholder()

  有一個場景,當你從網上載入了一張圖片到Imageview上,過了一段時間,想在同一個ImageView上展示另一張圖片,這個時候你就會去呼叫Picasso,進行二次請求,這時Picasso就會把之前的圖片進行清除,可能展示的是.placeholder()的圖片,給使用者並不是很好的體驗,如果呼叫了noPlaceholder(),就不會出現這種情況.


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .placeholder(R.mipmap.ic_launcher)  
  5.     .into(imageViewNoPlaceholder, new Callback() {
  6.         @Override
  7.         public void onSuccess() {
  8.             // 當上次載入完成後,進行二次載入
  9.             Picasso
  10.                 .with(context)
  11.                .load(UsageExampleListViewAdapter.eatFoodyImages[1])
  12.                .noPlaceholder()
  13.                .into(imageViewNoPlaceholder);
  14.         }
  15.         @Override
  16.         public void onError() {
  17.         }
  18.     });</font>
複製程式碼
呼叫resize(x, y)來自定義圖片的載入大小

如果圖片很大或者想自定義圖片的顯示樣式,可以呼叫該API來解決這個問題;


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .resize(600, 200)  
  5.     .into(imageViewResize);</font>
複製程式碼

呼叫`onlyScaleDown()來縮短圖片的載入計算時間

如果我們呼叫了resize(x,y)方法的話,Picasso一般會重新計算以改變圖片的載入質量,比如一張小圖變成一張大圖進行展示的時候,但是如果我們的原圖是比我們從新resize的新圖規格大的時候,我們就可以呼叫onlyScaleDown()來直接進行展示而不再重新計算.


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .resize(6000, 2000)
  5.     .onlyScaleDown() // 如果圖片規格大於6000*2000,將只會被resize
  6.     .into(imageViewResizeScaleDown);</font>
複製程式碼
對拉伸圖片的處理

如果圖片被操作了,可能在展示的時候就會比較醜,我們是想改變這種情景的,Picasso給我們提供了兩種選擇進行圖片展示,centerCrop() 或者centerInside().

  • centerCrop() - 圖片會被剪下,但是圖片質量看著沒有什麼區別
  • Inside()- 圖片會被完整的展示,可能圖片不會填充滿ImageView`,也有可能會被拉伸或者擠壓

  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .resize(600, 200)
  5.     .centerInside() 或者呼叫 .centerCrop()
  6.     .into(imageViewResizeCenterInside);</font>
複製程式碼

呼叫.fit()來智慧展示圖片

如果呼叫了該API, Picasso會對圖片的大小及ImageView進行測量,計算出最佳的大小及最佳的圖片質量來進行圖片展示,減少記憶體,並對檢視沒有影響;


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .fit()
  5.     .into(imageViewHero);</font>
複製程式碼
呼叫.priority()設定圖片載入的優先順序

如果一個螢幕上頂部圖片較大,而底部圖片較小,因為Picasso是非同步載入,所以小圖會先加載出來,但是對於使用者來說,更希望看到的是上面的圖片先載入,底部的圖片後加載,Picasso支援設定優先順序,分為HIGH, MEDIUM, 和 LOW,所有的載入預設優先順序為MEDIUM;


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .fit()
  5.     .priority(Picasso.Priority.HIGH)
  6.     .into(imageViewHero);</font>
複製程式碼

呼叫tag()為請求新增標記提升使用者體驗

  我們都知道,在一個ListView的子item中載入一張圖片是很常見的,這些圖片都來源於網路請求,如果這個listview有上千條資料,當用戶快速滑動的時候,每個item會不斷的被複用,當然Picasso的請求也不斷地進行請求,取消請求,再次請求,再次取消的操作(對螢幕外的自動取消請求),但是如果有一個方案,可以在使用者在快速滑動的時候全部停止請求,只有在滑動停止時再去請求,就非常完美了;

Picasso提供了三種設定Tag的方式

  • 暫停標記 pauseTag()
  • 可見標記 resumeTag()
  • 取消標記 cancleTag()

pauseTag() 和 resumeTag()的用法

在圖片請求時新增標記


  1. <font color="rgb(85, 85, 85)">Picasso
  2.     .with(context)
  3.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  4.     .tag("Profile ListView") //引數為 Object
  5.     .into(imageViewWithTag);</font>
複製程式碼
然後讓listview實現滑動監聽



  1. <font color="rgb(85, 85, 85)">@Override
  2.   public void onScrollStateChanged(AbsListView view, int scrollState) {
  3.     final Picasso picasso = Picasso.with(context);
  4.     if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {
  5.           picasso.resumeTag("Profile ListView");
  6.     } else {
  7.           picasso.pauseTag("Profile ListView");
  8.     }
  9.   }</font>
複製程式碼
cancleTag()的使用場景

試想一下,當你在瀏覽購物車的時候,這個時候就會去展示所有被選中item的圖片資源,如果這個時候使用者點選了購買按鈕,就會彈出一個progressdialog去請求資料以進行頁面跳轉,這個時候原來的請求就需要取消掉了;


  1. <font color="rgb(85, 85, 85)">public void buyButtonClick(View v) {
  2.      showDiaolg();
  3.     // 取消網路請求
  4.     Picasso
  5.         .with(context)
  6.         .cancelTag("ShoppingCart");
  7. }</font>
複製程式碼

注意:如果tag狀態為pause或者resume的話,Picasso會對tag持有一個引用,如果此時使用者退出了當前Activity,垃圾回收機制進行回收的時候,就會出現記憶體洩露,所以需要在onDestory()方法中進行相應處理;

.fetch() , .get() 及 Target之間的區別
  • .fetch() - 該方法會在後臺非同步載入一張圖片,但是不會展示在ImageView上,也不會返回Bitmap,這個方法只是為了將獲取到的資源載入到本地和記憶體中,為了後期載入縮短時間;
  • .get() - 該方法也是一個非同步執行緒,不過載入完成後會返回一個Bitmap,但是需要注意,該方法不能在主執行緒中呼叫,因為會造成執行緒阻塞;
  • Target - 我們之前呼叫.into()方法,只是將獲取到的資源載入到ImageView中,但我們還可以將資源作為回撥放到Target中,上程式碼:

  1. <font color="rgb(85, 85, 85)">private Target target = new Target() {
  2.     @Override
  3.     public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
  4.         //載入成功後會得到一個bitmap,可以自定義操作
  5.     }
  6.     @Override
  7.     public void onBitmapFailed(Drawable errorDrawable) {
  8.         // 載入失敗進行相應處理
  9.     }
  10.     @Override
  11.     public void onPrepareLoad(Drawable placeHolderDrawable) {
  12.     }
  13. };
  14. Picasso
  15.     .with(context)
  16.     .load(UsageExampleListViewAdapter.eatFoodyImages[0])
  17.     .into(target);</font>
複製程式碼

注意:你可以使用.get()或者Target獲取圖片的Bitmap,但是當你使用Target時,不能使用匿名內部類的方式,因為垃圾回收機制在你獲取不到Bitmap的時候會把物件回收;

Picasso在自定義Notifications上的使用

Picasso有一個功能是可以載入圖片到RemoteViews上,而RemoteViews是用在Widgets及自定義notification佈局上的,下面通過一個小的示例來看Picasso是如何起作用的;


  1. <font color="rgb(85, 85, 85)"> private void testRemoteView() {
  2.         RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.item_picasso);
  3.         remoteViews.setImageViewResource(R.id.iv_remoteview,R.mipmap.abc);
  4.         remoteViews.setTextViewText(R.id.tv_title,"This Title");
  5.         remoteViews.setTextViewText(R.id.tv_desc,"This desc");
  6.         remoteViews.setTextColor(R.id.tv_title,getResources().getColor(android.R.color.black));
  7.         remoteViews.setTextColor(R.id.tv_desc,getResources().getColor(android.R.color.holo_blue_bright));
  8.         NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this)
  9.                                                 .setSmallIcon(R.mipmap.notifation)
  10.                                                 .setContentTitle("Context Title")
  11.                                                 .setContentText("Content Text")
  12.                                                 .setContent(remoteViews)
  13.                                                 .setPriority(NotificationCompat.PRIORITY_MIN);
  14.         Notification notification = builder.build();
  15.         if (Build.VERSION.SDK_INT > 16){
  16.             notification.bigContentView = remoteViews;
  17.         }
  18.         NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
  19.         mNotificationManager.notify(NOTIFICATION_ID,notification);
  20.         Picasso.with(MainActivity.this)
  21.                 .load("http://www.jycoder.com/json/Image/3.jpg")
  22.                 .into(remoteViews,R.id.iv_remoteview,NOTIFICATION_ID,notification);
  23.     }</font>
複製程式碼

上面可以看到,Picasso的使用也是非常簡單,只需要呼叫.into()的另一個過載方法即可:
.into(.widget.RemoteViews remoteViews, int viewId, int notificationId, android.app.Notification notification)

效果如下