Android圖片載入框架Picasso使用教程 (三)
前面我們對Picasso的用法有了一定得了解,下面就分析一下一些特殊情況下,Picasso的用法.
呼叫.noFade()Picasso的預設圖片載入方式有一個淡入的效果,如果呼叫了noFade(),載入的圖片將直接顯示在ImageView上
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .placeholder(R.mipmap.ic_launcher)
- .error(R.mipmap.future_studio_launcher)
- .noFade()
- .into(imageViewFade);</font>
呼叫.noPlaceholder()
有一個場景,當你從網上載入了一張圖片到Imageview上,過了一段時間,想在同一個ImageView上展示另一張圖片,這個時候你就會去呼叫Picasso,進行二次請求,這時Picasso就會把之前的圖片進行清除,可能展示的是.placeholder()的圖片,給使用者並不是很好的體驗,如果呼叫了noPlaceholder(),就不會出現這種情況.
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .placeholder(R.mipmap.ic_launcher)
- .into(imageViewNoPlaceholder, new Callback() {
- @Override
- public void onSuccess() {
- // 當上次載入完成後,進行二次載入
- Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[1])
- .noPlaceholder()
- .into(imageViewNoPlaceholder);
- }
- @Override
- public void onError() {
- }
- });</font>
呼叫resize(x, y)來自定義圖片的載入大小
如果圖片很大或者想自定義圖片的顯示樣式,可以呼叫該API來解決這個問題;
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .resize(600, 200)
- .into(imageViewResize);</font>
呼叫`onlyScaleDown()來縮短圖片的載入計算時間
如果我們呼叫了resize(x,y)方法的話,Picasso一般會重新計算以改變圖片的載入質量,比如一張小圖變成一張大圖進行展示的時候,但是如果我們的原圖是比我們從新resize的新圖規格大的時候,我們就可以呼叫onlyScaleDown()來直接進行展示而不再重新計算.
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .resize(6000, 2000)
- .onlyScaleDown() // 如果圖片規格大於6000*2000,將只會被resize
- .into(imageViewResizeScaleDown);</font>
對拉伸圖片的處理
如果圖片被操作了,可能在展示的時候就會比較醜,我們是想改變這種情景的,Picasso給我們提供了兩種選擇進行圖片展示,centerCrop() 或者centerInside().
- centerCrop() - 圖片會被剪下,但是圖片質量看著沒有什麼區別
-
Inside()- 圖片會被完整的展示,可能圖片不會填充滿ImageView`,也有可能會被拉伸或者擠壓
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .resize(600, 200)
- .centerInside() 或者呼叫 .centerCrop()
- .into(imageViewResizeCenterInside);</font>
呼叫.fit()來智慧展示圖片
如果呼叫了該API, Picasso會對圖片的大小及ImageView進行測量,計算出最佳的大小及最佳的圖片質量來進行圖片展示,減少記憶體,並對檢視沒有影響;
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .fit()
- .into(imageViewHero);</font>
呼叫.priority()設定圖片載入的優先順序
如果一個螢幕上頂部圖片較大,而底部圖片較小,因為Picasso是非同步載入,所以小圖會先加載出來,但是對於使用者來說,更希望看到的是上面的圖片先載入,底部的圖片後加載,Picasso支援設定優先順序,分為HIGH, MEDIUM, 和 LOW,所有的載入預設優先順序為MEDIUM;
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .fit()
- .priority(Picasso.Priority.HIGH)
- .into(imageViewHero);</font>
呼叫tag()為請求新增標記提升使用者體驗
我們都知道,在一個ListView的子item中載入一張圖片是很常見的,這些圖片都來源於網路請求,如果這個listview有上千條資料,當用戶快速滑動的時候,每個item會不斷的被複用,當然Picasso的請求也不斷地進行請求,取消請求,再次請求,再次取消的操作(對螢幕外的自動取消請求),但是如果有一個方案,可以在使用者在快速滑動的時候全部停止請求,只有在滑動停止時再去請求,就非常完美了;
Picasso提供了三種設定Tag的方式
- 暫停標記 pauseTag()
- 可見標記 resumeTag()
- 取消標記 cancleTag()
pauseTag() 和 resumeTag()的用法
在圖片請求時新增標記
- <font color="rgb(85, 85, 85)">Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .tag("Profile ListView") //引數為 Object
- .into(imageViewWithTag);</font>
然後讓listview實現滑動監聽
- <font color="rgb(85, 85, 85)">@Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- final Picasso picasso = Picasso.with(context);
- if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {
- picasso.resumeTag("Profile ListView");
- } else {
- picasso.pauseTag("Profile ListView");
- }
- }</font>
cancleTag()的使用場景
試想一下,當你在瀏覽購物車的時候,這個時候就會去展示所有被選中item的圖片資源,如果這個時候使用者點選了購買按鈕,就會彈出一個progressdialog去請求資料以進行頁面跳轉,這個時候原來的請求就需要取消掉了;
- <font color="rgb(85, 85, 85)">public void buyButtonClick(View v) {
- showDiaolg();
- // 取消網路請求
- Picasso
- .with(context)
- .cancelTag("ShoppingCart");
- }</font>
注意:如果tag狀態為pause或者resume的話,Picasso會對tag持有一個引用,如果此時使用者退出了當前Activity,垃圾回收機制進行回收的時候,就會出現記憶體洩露,所以需要在onDestory()方法中進行相應處理;
.fetch() , .get() 及 Target之間的區別- .fetch() - 該方法會在後臺非同步載入一張圖片,但是不會展示在ImageView上,也不會返回Bitmap,這個方法只是為了將獲取到的資源載入到本地和記憶體中,為了後期載入縮短時間;
- .get() - 該方法也是一個非同步執行緒,不過載入完成後會返回一個Bitmap,但是需要注意,該方法不能在主執行緒中呼叫,因為會造成執行緒阻塞;
- Target - 我們之前呼叫.into()方法,只是將獲取到的資源載入到ImageView中,但我們還可以將資源作為回撥放到Target中,上程式碼:
- <font color="rgb(85, 85, 85)">private Target target = new Target() {
- @Override
- public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
- //載入成功後會得到一個bitmap,可以自定義操作
- }
- @Override
- public void onBitmapFailed(Drawable errorDrawable) {
- // 載入失敗進行相應處理
- }
- @Override
- public void onPrepareLoad(Drawable placeHolderDrawable) {
- }
- };
- Picasso
- .with(context)
- .load(UsageExampleListViewAdapter.eatFoodyImages[0])
- .into(target);</font>
注意:你可以使用.get()或者Target獲取圖片的Bitmap,但是當你使用Target時,不能使用匿名內部類的方式,因為垃圾回收機制在你獲取不到Bitmap的時候會把物件回收;
Picasso在自定義Notifications上的使用Picasso有一個功能是可以載入圖片到RemoteViews上,而RemoteViews是用在Widgets及自定義notification佈局上的,下面通過一個小的示例來看Picasso是如何起作用的;
- <font color="rgb(85, 85, 85)"> private void testRemoteView() {
- RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.item_picasso);
- remoteViews.setImageViewResource(R.id.iv_remoteview,R.mipmap.abc);
- remoteViews.setTextViewText(R.id.tv_title,"This Title");
- remoteViews.setTextViewText(R.id.tv_desc,"This desc");
- remoteViews.setTextColor(R.id.tv_title,getResources().getColor(android.R.color.black));
- remoteViews.setTextColor(R.id.tv_desc,getResources().getColor(android.R.color.holo_blue_bright));
- NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this)
- .setSmallIcon(R.mipmap.notifation)
- .setContentTitle("Context Title")
- .setContentText("Content Text")
- .setContent(remoteViews)
- .setPriority(NotificationCompat.PRIORITY_MIN);
- Notification notification = builder.build();
- if (Build.VERSION.SDK_INT > 16){
- notification.bigContentView = remoteViews;
- }
- NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
- mNotificationManager.notify(NOTIFICATION_ID,notification);
- Picasso.with(MainActivity.this)
- .load("http://www.jycoder.com/json/Image/3.jpg")
- .into(remoteViews,R.id.iv_remoteview,NOTIFICATION_ID,notification);
- }</font>
上面可以看到,Picasso的使用也是非常簡單,只需要呼叫.into()的另一個過載方法即可:
.into(.widget.RemoteViews remoteViews, int viewId, int notificationId, android.app.Notification notification)
效果如下