2016-06-13 15 views
0

我使用下面的代碼加載從服務器鏡像在RecyclerView重裝加載的圖像:凌空ImageLoader的上滾動

imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader(); 
    imageLoader.get(image_url, ImageLoader.getImageListener(holder.title_img, R.drawable.reads, android.R.drawable.ic_dialog_alert)); 
    holder.title_img.setImageUrl(image_url, imageLoader); 

的問題是,當我再次向上滾動時,加載的圖像被重新加載。如何以避免這...

回答

-1

圖像將不會從URL重新加載,但從緩存。 recyclerview將圖像保存在內存中並「回收」視圖以節省內存。如果您不想回收需要使用的視圖,例如使用ListView而不是RecyclerView。

+0

如果緩存的圖像重用,那麼shud不是一個滯後。此外,當我斷開中間的互聯網時,圖像抖動以任何方式再現。但是,這些都不是這樣的... –

+0

甚至listview可以回收視圖! –

+0

普通列表視圖不回收視圖,Recycler View是ListView的一個擴展,它向您顯示onBindViewHolder,並且此方法創建或回收視圖。 – rik194

0

您應該在設備中緩存圖像以防止再次加載圖像。

創建一個名爲LruBitmapCache.java的類並添加以下代碼。這個類負責在磁盤上緩存網絡映像。

LruBitmapCache.java

import com.android.volley.toolbox.ImageLoader.ImageCache; 

import android.graphics.Bitmap; 
import android.support.v4.util.LruCache; 

public class LruBitmapCache extends LruCache<String, Bitmap> implements 
     ImageCache { 
    public static int getDefaultLruCacheSize() { 
     final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 
     final int cacheSize = maxMemory/8; 

     return cacheSize; 
    } 

    public LruBitmapCache() { 
     this(getDefaultLruCacheSize()); 
    } 

    public LruBitmapCache(int sizeInKiloBytes) { 
     super(sizeInKiloBytes); 
    } 

    @Override 
    protected int sizeOf(String key, Bitmap value) { 
     return value.getRowBytes() * value.getHeight()/1024; 
    } 

    @Override 
    public Bitmap getBitmap(String url) { 
     return get(url); 
    } 

    @Override 
    public void putBitmap(String url, Bitmap bitmap) { 
     put(url, bitmap); 
    } 
} 

創建名爲AppController.java類,並粘貼以下內容。這是一個單例類,用於初始化所需類的全局實例。凌空相關的所有對象都在這裏初始化:

import YourPakageName.LruBitmapCache; 
import android.app.Application; 
import android.text.TextUtils; 

import com.android.volley.Request; 
import com.android.volley.RequestQueue; 
import com.android.volley.toolbox.ImageLoader; 
import com.android.volley.toolbox.Volley; 

public class AppController extends Application { 

    public static final String TAG = AppController.class.getSimpleName(); 

    private RequestQueue mRequestQueue; 
    private ImageLoader mImageLoader; 
    LruBitmapCache mLruBitmapCache; 

    private static AppController mInstance; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     mInstance = this; 
    } 

    public static synchronized AppController getInstance() { 
     return mInstance; 
    } 

    public RequestQueue getRequestQueue() { 
     if (mRequestQueue == null) { 
      mRequestQueue = Volley.newRequestQueue(getApplicationContext()); 
     } 

     return mRequestQueue; 
    } 

    public ImageLoader getImageLoader() { 
     getRequestQueue(); 
     if (mImageLoader == null) { 
      getLruBitmapCache(); 
      mImageLoader = new ImageLoader(this.mRequestQueue, mLruBitmapCache); 
     } 

     return this.mImageLoader; 
    } 

    public LruBitmapCache getLruBitmapCache() { 
     if (mLruBitmapCache == null) 
      mLruBitmapCache = new LruBitmapCache(); 
     return this.mLruBitmapCache; 
    } 

    public <T> void addToRequestQueue(Request<T> req, String tag) { 
     req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); 
     getRequestQueue().add(req); 
    } 

    public <T> void addToRequestQueue(Request<T> req) { 
     req.setTag(TAG); 
     getRequestQueue().add(req); 
    } 

    public void cancelPendingRequests(Object tag) { 
     if (mRequestQueue != null) { 
      mRequestQueue.cancelAll(tag); 
     } 
    } 
} 

現在打開你的AndroidManifest.xml文件,並在標籤中添加Application.java類:

<application 
    android:name="YourPakageName.app.AppController"> ....</application> 

之後,它進入您的適配器,並添加如下代碼:

private Context context; 
     ImageLoader imageLoader = 
YourPakageName.AppController.getInstance().getImageLoader(); 
     private RequestQueue queue; 
     private LruCache<Integer, Bitmap> imageCache; 

和:

public MyCustommAdapter(Context context, int resource, List<YourModel> objects) { 
      super(context, resource, objects); 
      this.context = context; 
      this.postList = objects; 
      final int maxMemory = (int)(Runtime.getRuntime().maxMemory() /1024); 
      final int cacheSize = maxMemory/5; 
      imageCache = new LruCache<Integer, Bitmap>(cacheSize); 

      queue = Volley.newRequestQueue(context); 
} 

現在,你可以簡單地得到URL的圖像,並顯示在列表視圖:

imageLoader.get(image_url, new ImageLoader.ImageListener() { 

       @Override 
       public void onErrorResponse(VolleyError error) { 
        //Log.e(TAG, "Image Load Error: " + error.getMessage()); 
       } 

       @Override 
       public void onResponse(ImageLoader.ImageContainer response, boolean arg1) { 
        if (response.getBitmap() != null) { 
         // load image into imageview 
         holder.title_img.setImageBitmap(response.getBitmap()); 
        } 
       } 
      }); 
+0

爲什麼我們需要齊齊寫出所有這些。排球應該提供內置的功能來做到這一點..無論如何,如果我能得到時間,我會嘗試你的代碼一次..現在我正在嘗試畢加索圖書館... –

0

的官方文檔顯示,當需要寫入LruBitmapCache.java到達時,內存緩存的心臟的圖像是在下面的代碼片斷:

final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 

    // Use 1/8th of the available memory for this memory cache. 
    final int cacheSize = maxMemory/8; 

的AndroidCaching Bitmap documentation特別指出

注意:在本例中,八分之一的應用程序內存分配給我們的緩存。在普通/ hdpi設備上,這是最低大約4MB(32/8)。在800x480分辨率的設備上充滿圖像的全屏GridView將使用大約1.5MB(800 * 480 * 4字節),因此這會在內存中緩存至少約2.5頁的圖像。

我做了一個小實驗像什麼哈立德Rostampour建議:

maxMemory/5; 

但maxMemory設置爲較低的數字是一個流暢的體驗,就像Facebook的應用程序體驗更好。

我用這個Facebook-like app做了一個基本測試,這是一個很好的教程,在Volley上有一個很好的教程,它實現了Khalid建議的內容,但是當maxMemory/8甚至maxMemory時,我都遇到了滾動來試圖達到理想的平滑度/ 3.

我終於做出了選擇設置:

maxMemory/2; 

你猜怎麼着,經驗模仿了Facebook應用程序的平滑度(甚至更好)。

因此,根據您的需要,您可以在應用程序的某些部分中爲您的映像緩存例程分配多少內存。

構建應用時需要考慮的最終決定因素就像我參考的示例用戶體驗因子。我的第三週在android開發中,我意識到開發人員需要在性能和用戶體驗之間取得平衡,我發現這是一個很好的設計模式,我相信,即使是經過驗證的應用程序,我們經常使用它一樣。