2013-03-12 45 views
0

我寫了下面的代碼,使用CWAC Endless Adapter實現包含ImageViews的ListView的無限滾動。這些圖像是從點播網絡上檢索與AsyncTasks:使用cwac無盡的適配器加載圖像無盡的ListView

package com.myproject.ui.adapter; 

import java.io.InputStream; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 

import android.content.Context; 
import android.content.Intent; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.AsyncTask; 
import android.util.LruCache; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.ImageView; 

import com.commonsware.cwac.endless.EndlessAdapter; 

public class MyThumbsAdapter extends EndlessAdapter { 

    public static class FetchThumbTask extends AsyncTask<String, Void, Bitmap> { 

     private final Context mContext; 
     private final BaseAdapter mAdapter; 
     private final String mThumbId; 
     private final View mView; 

     public FetchThumbTask(Context context, BaseAdapter adapter, View view, String thumbId) { 
      mContext = context; 
      mAdapter = adapter; 
      mView = view; 
      mThumbId = thumbId; 
     } 

     @Override 
     protected Bitmap doInBackground(String... arg0) { 
      Bitmap bitmap = null; 
      if (cache.get(mThumbId) == null) { 
       // Fetch thumbnail 
       try { 
        URL url = new URL(...); 
        InputStream is = url.openStream(); 
        bitmap = BitmapFactory.decodeStream(is); 
        cache.put(mThumbId, bitmap); 
       } catch (Exception e) { 
        ... 
       } 
      } 
      return bitmap; 
     } 

     @Override 
     protected void onPostExecute(Bitmap bitmap) { 
       // Set the loaded image on the ImageView 
         ImageView imageView = (ImageView) mView.findViewById(R.id.thumb_image); 
      if (imageView != null) { 
       imageView.setImageBitmap(bitmap); 
      } 
     } 
    } 

    public static class MyThumbsBaseAdapter extends BaseAdapter { 

     private final Context mContext; 
     private final List<String> mThumbIds = new ArrayList<String>(); 

     public MyThumbsBaseAdapter(Context context) { 
      mContext = context; 
     } 

     public void addThumbIds(List<String> thumbIds) { 
      mThumbIds.addAll(thumbIds); 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
      String thumbId = mThumbIds.get(position); 
      View rootView = convertView; 

      if (rootView == null) { 
       rootView = LayoutInflater.from(parent.getContext()).inflate(
         R.layout.thumbnails, null); 
      } 
      ImageView imageView = 
        (ImageView) rootView.findViewById(R.id.doodle_thumb_image); 

      Bitmap bitmap = cache.get(thumbId); 
      if (bitmap == null) { 
       loadThumbBitmap(rootView, thumbId); 
      } else if (imageView != null) { 
       imageView.setImageBitmap(bitmap); 
      } 

      return rootView; 
     } 

     @Override 
     public int getCount() { 
      return mThumbIds.size(); 
     } 

     @Override 
     public Object getItem(int position) { 
      return null; 
     } 

     @Override 
     public long getItemId(int position) { 
      return 0; 
     } 

     private void loadThumbBitmap(View view, String thumbId) { 
      new FetchThumbTask(mContext, this, view, thumbId) 
       .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
     } 
    } 

    static { 
     int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 
     int cacheSize = maxMemory/8; 
     cache = new LruCache<String, Bitmap>(cacheSize) { 
      @Override 
      protected int sizeOf(String key, Bitmap bitmap) { 
       // The cache size will be measured in kilobytes rather than 
       // number of items. 
       return bitmap.getByteCount()/1024; 
      } 
     }; 
    } 

    private static final LruCache<String, Bitmap> cache; 

    private List<String> mThumbIdsCache; 

    public MyThumbsAdapter(Context context) { 
     super(new MyThumbsBaseAdapter(context)); 
    } 

    @Override 
    protected View getPendingView(ViewGroup parent) { 
     return LayoutInflater.from(parent.getContext()) 
       .inflate(R.layout.loading_thumb, null); 
    } 

    @Override 
    protected boolean cacheInBackground() throws Exception { 
     JsonReader reader = // Retrieve thumb ids list from server 
     mThumbIdsCache = // Returned thumb ids list 
     return true; 
    } 

    @Override 
    protected void appendCachedData() { 
     MyThumbsBaseAdapter adapter = (MyThumbsBaseAdapter) getWrappedAdapter(); 
     adapter.addThumbIds(mThumbIdsCache); 
    } 
} 

我使用LruCache緩存從網絡加載的位圖。問題是我在測試Nexus 7時會看到大量的緩存未命中,這應該有足夠的內存空間。這會導致圖像在我向上/向下滾動ListView時彈出。

更糟糕的是,我看到應用程序崩潰與OutOfMemory錯誤,但我不能一貫重現。

我在這裏做錯了什麼?我應該不是爲每個圖像觸發單獨的AsyncTasks嗎?

編輯:我還應該提到我下載的圖像是預先縮放的。

回答

1

我想你需要做的是在屏幕上顯示Thumbnails而不是位圖圖像。您可以生成Thumbnails並根據您的尺寸要求進行顯示。並且每當用戶點擊Thumb時,只需取原路徑並設置壁紙即可。

另一種選擇是您可以使用Universal Image Loader,它可以幫助您緩存光盤中的圖像(如SD card或您的應用程序的Internal memory)。所以問題Out of Memory可以解決。

而且對於顯示位圖的最佳做法,Displaying Bitmaps Efficiently將有所幫助。

編輯:

使用下面爲您的應用程序配置。這將緩存緩存目錄中的應用程序。

File cacheDir = new File(this.getCacheDir(), "cwac"); 
if (!cacheDir.exists()) 
    cacheDir.mkdir(); 

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
      CWAC.this) 
      .threadPoolSize(5) 
      .threadPriority(Thread.MIN_PRIORITY + 3) 
      .denyCacheImageMultipleSizesInMemory() 
      // .memoryCache(new UsingFreqLimitedMemoryCache(2000000)) // You 
      // can pass your own memory cache implementation 
      .memoryCacheSize(1048576 * 10) 
      // 1MB=1048576 *declare 20 or more size if images are more than 
      // 200 
      .discCache(new UnlimitedDiscCache(cacheDir)) 
      // You can pass your own disc cache implementation 
      //.defaultDisplayImageOptions(DisplayImageOptions.createSimple()) 
      .build(); 
+0

謝謝!編輯:我還應該提到,我下載的圖像是預先縮放的。 – Simian 2013-03-12 06:44:30

+0

我錯過了..抱歉沒有看。 – 2013-03-12 06:48:24

+0

不幸的是,即使在配置其memoryCacheSize之後,使用ImageLoader的效果似乎比我上面的LruCache解決方案還差。 – Simian 2013-03-12 07:25:43