我試圖實現與UrlImageViewHelper(https://github.com/koush/UrlImageViewHelper)非常類似的內容,您可以輕鬆使用簡單的一行代碼,從url加載圖像,並且如果圖像已經下載,它將從緩存加載。主要區別在於我想獲得相同的效果,但不是從網址下載,而是希望通過我自己的客戶端 - 服務器通信從我自己的服務器接收圖像。我的服務器上的每個圖像都可以用字符串唯一標識,並將其用作圖像的標識。我的主要想法是這樣的:使用一個LRU緩存來保存圖像,但不是拿着位圖(這是非常大的),我想保存原始圖像數據二進制,所以我可以使用相同的圖像來構建視具體情況而定,按需提供不同尺寸和質量的位圖。緩存圖像 - 在加載不同的位圖或ImageView的活動後未收集位圖
這是迄今爲止我的執行:
public class ImageHandler {
private static class BitmapCache extends LruCache<String, byte[]>
{
public WigoBitmapCache(int maxSize) {
super(maxSize);
}
@Override
protected int sizeOf(String key, byte[] value) {
return value.length;
}
}
private static class ImageHandlerThread extends Thread
{
/* THIS THREAD WILL DECODE THE IMAGE AND SET THE BITMAP TO THE IMAGEVIEW IN THE BACKGROUND */
Activity activity;
ImageView imageView;
byte[] imageBytes;
public ImageHandlerThread(Activity activity, ImageView imageView, byte[] imageBytes)
{
this.activity=activity;
this.imageView=imageView;
this.imageBytes=imageBytes;
}
public void run() {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
int factor1=o.outHeight/height;
int factor2=o.outWidth/width;
/* height and width are for now constant */
o = null;
o = new BitmapFactory.Options();
if (factor1>factor2)
o.inSampleSize=factor1;
else
o.inSampleSize=factor2;
Bitmap bit = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length,o);
setBitmap(bit);
bit = null;
}
private void setBitmap(final Bitmap bit) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bit);
}
});
}
}
private static class QueueItem
{ /*USED TO HOLD INFO ABOUT THE IMAGE REQUEST UNTIL THE IMAGE GETS FROM THE SERVER */
String imageName;
Activity activity;
ImageView imageView;
public QueueItem(String imageName, Activity activity, ImageView imageView)
{
this.imageName=imageName;
this.activity = activity;
this.imageView = imageView;
}
}
private BitmapCache cache; // this cache holds the image binaries
private ArrayList<QueueItem> queue; // this queue holds the info about the request, until the server sends the image
public ImageHandler(int maxSize)
{
cache=new BitmapCache(maxSize);
queue = new ArrayList<QueueItem>();
}
public synchronized void setBitmap(Activity activity, ImageView imageView, String imageName)
{
byte[] imageBytes = cache.get(imageName);
if (imageBytes==null)
{
QueueItem item = new QueueItem(imageName, activity, imageView);
queue.add(item);
/* HERE IS THE CODE TO RETRIEVE THE IMAGE BINARY FROM MY SERVER, THIS CODE WORKS FINE, SO THERE IS NO REASON TO BOHER YOU WITH IT */
}
else
{
ImageHandlerThread thread = new ImageHandlerThread(activity, imageView, imageBytes);
thread.start();
}
}
public synchronized void insert (String imageName, byte[] imageBytes)
{
/* THIS METHOD IS THE CALLBACK THAT IS CALLED WHEN THE IMAGE BINARY IS RECEIVED FROM THE SERVER */
cache.put(imageName, imageBytes);
for (QueueItem item: queue)
{
if (item.imageName.equals(imageName))
{
ImageHandlerThread thread = new ImageHandlerThread(item.activity, item.imageView, imageBytes);
thread.start();
queue.remove(item);
}
}
}
}
基本上,這裏的主要方法是setBitmap(),它獲取的活動,需要的位圖的ImageView,圖像名稱的名稱。如果圖像已存在於緩存中,則會啓動一個新線程將字節解碼爲適當大小的位圖,並將位圖設置爲imageView。如果圖像不存在於緩存中,則將請求放入隊列中,直到接收到圖像,從服務器檢索圖像,然後啓動與之前相同的線程。
所有這些工作絕對沒問題,問題是當imageView被設置爲圖像的另一個位圖或者甚至當活動被破壞時,位圖仍駐留在內存中,並且不被GC收集。
起初,我認爲這是因爲我保持對活動的引用,並且引用使活動保持活躍狀態,但似乎並非如此,對活動的引用非常短暫,圖像從服務器到達,此參考被清除。
我用這個實現快速地運行內存不足,我不知道爲什麼或者該怎麼做來修復它。我創建的位圖不會收集,儘管我不保留對它們的引用。這可能是我解碼圖像的方式的一個神器嗎?或者線程是否保持沒有正確收集的引用?任何人有任何想法?