2012-12-18 46 views
3

我想创建一个简单的文件管理器,我有一个缩略图(位图)加载问题。我想利用这些技巧使用的AsyncTask和LRU缓存:位图不显示使用lrucache和asynctask

http://developer.android.com/training/displaying-bitmaps/index.html

一切都没事,直到我试图实现LRU缓存。我的意思是,没有lru缓存位图加载,但滚动它不光滑。使用lru缓存,滚动是平滑的,但位图不需要立即加载。我必须向下滚动,然后再向下滚动,然后加载位图。

这里是我的意思(对不起,质量差):

http://www.youtube.com/watch?v=Xfkd6Esx7D0

这里是我的ArrayAdapter:

public class AdapterFiles extends ArrayAdapter<String>{ 
private int resource; 
private static final String PREFERENCES_NAME = "Preferences"; 
private static final String CHECKBOX_FIELD = "thumbnails"; 
private static final String LIST_FIELD = "colorlist"; 

private SharedPreferences preferences; 
private boolean thumbnails; 
private OnClickListener onItemMenuClickListener; 
private String item; 
private ViewHolder viewHolder; 
public static ArrayList<Integer> selectedIds = new ArrayList<Integer>(); 
private String colorrow; 
private final ThumbnailLoader tnloader = new ThumbnailLoader(); 


public AdapterFiles(Context context, int textViewResourceId, int label, List<String> objects) { 
     super(context, textViewResourceId, objects); 
     preferences = context.getSharedPreferences(PREFERENCES_NAME, Activity.MODE_PRIVATE); 
     thumbnails = preferences.getBoolean(CHECKBOX_FIELD, false); 
     resource = textViewResourceId;   
} 

static class ViewHolder { 
    TextView label; 
    ImageView ikonka; 
    TextView size; 
    TextView date; 
    ImageButton context_menu; 

} 


@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    RelativeLayout RowView; 
     item = getItem(position); 
     preferences.getString(LIST_FIELD, "#FF0099CC"); 



     if(convertView == null) { 
     RowView = new RelativeLayout(getContext()); 
     LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     inflater.inflate(resource, RowView, true); 
     viewHolder = new ViewHolder(); 
     viewHolder.label = (TextView)RowView.findViewById(R.id.label); 
     viewHolder.ikonka = new ImageView(getContext()); 
     viewHolder.ikonka = (ImageView)RowView.findViewById(R.id.icon); 
     viewHolder.ikonka.setTag(item); 
     viewHolder.size = (TextView)RowView.findViewById(R.id.size); 
     viewHolder.date = (TextView)RowView.findViewById(R.id.date); 
     viewHolder.context_menu = (ImageButton)RowView.findViewById(R.id.context_menu); 
     viewHolder.context_menu.setFocusable(false); 
     viewHolder.context_menu.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { 
       if(onItemMenuClickListener != null) onItemMenuClickListener.onClick(v); 
      } 
     }); 
     RowView.setTag(viewHolder); 
     } else { 
      RowView = (RelativeLayout)convertView; 
      viewHolder = (ViewHolder) RowView.getTag(); 
     } 


      colorrow = "#FF99D6EB"; 

     RowView.setBackgroundColor(selectedIds.contains(position) ? Color.parseColor(colorrow) : android.R.color.transparent); 


     File file = new File(item); 
     if (file.isDirectory()){ 
      if(file.canRead()){ 
      viewHolder.ikonka.setImageResource(R.drawable.folder); 
      } 
      else{ 
      viewHolder.ikonka.setImageResource(R.drawable.foldernoway); 
      } 
     }else if(item.endsWith(".doc") || item.endsWith(".docx")){ 
      viewHolder.ikonka.setImageResource(R.drawable.docs);} 

     else if(item.endsWith(".xls") || item.endsWith(".xlsx")){ 
      viewHolder.ikonka.setImageResource(R.drawable.xls);} 

     else if(item.endsWith(".ppt") || item.endsWith(".pptx")){ 
      viewHolder.ikonka.setImageResource(R.drawable.ppt);} 

     else if(item.endsWith(".txt")){ 
      viewHolder.ikonka.setImageResource(R.drawable.txt);} 

     else if(item.endsWith(".mp3") || item.endsWith(".wma") || item.endsWith(".m4a") || item.endsWith(".ogg")){ 
      viewHolder.ikonka.setImageResource(R.drawable.music);} 

     else if(item.endsWith(".apk")){ 
      viewHolder.ikonka.setImageResource(R.drawable.android);} 

     else if(item.endsWith(".pdf")){ 
      viewHolder.ikonka.setImageResource(R.drawable.adobe);} 

     else if(item.endsWith(".jpg") || item.endsWith(".JPG") || item.endsWith(".png") || item.endsWith(".jpeg")){ 



      if(thumbnails == false){ 
      viewHolder.ikonka.setImageResource(R.drawable.image); 
      }else{ 

       tnloader.loadBitmap(item, viewHolder.ikonka); 
      } 
      }   
     else if(item.endsWith(".avi") || item.endsWith(".3gp") || item.endsWith(".mp4")){ 


       viewHolder.ikonka.setImageResource(R.drawable.video); 

     } 
     else if(item.endsWith(".rar") || item.endsWith(".zip") || item.endsWith(".tar")){ 
      viewHolder.ikonka.setImageResource(R.drawable.zip);} 

     else{ 
      viewHolder.ikonka.setImageResource(R.drawable.noname); 
     } 



     viewHolder.label.setText(file.getName()); 

     if (file.isDirectory()){ 
     viewHolder.size.setText(R.string.folder);} 
     else{ 
      double bytes = file.length(); 
      double kilobytes = (bytes/1024); 
      double megabytes = (kilobytes/1024); 
      if (bytes < 6000){ 
     viewHolder.size.setText(bytes + " b"); 
      }else{ 
     viewHolder.size.setText(String.format("%.2f MB", megabytes));}  
     } 

     Date lastModDate = new Date(file.lastModified()); 
     SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 
     String formattedDateString = formatter.format(lastModDate); 

     viewHolder.date.setText(formattedDateString); 

     viewHolder.context_menu.setTag(new Integer(position));   

     return RowView; 


    } 

    public void setOnItemMenuClickListener(
     OnClickListener onItemMenuClickListner) { 
    this.onItemMenuClickListener = onItemMenuClickListner; 
    } 
} 

和ThumbnailLoader:

public class ThumbnailLoader { 

Context context; 
int memClass = 80; 


public void loadBitmap(String filePath, ImageView imageView) { 
    final String imageKey = String.valueOf(filePath); 

    final Bitmap bitmap = getBitmapFromMemCache(imageKey); 
    if (bitmap != null) { 
     imageView.setImageBitmap(bitmap); 
    } else { 
     imageView.setImageResource(R.drawable.image); 
     BitmapWorkerTask task = new BitmapWorkerTask(imageView); 
     task.execute(filePath); 
    } 

} 



public static boolean cancelPotentialWork(String data, ImageView imageView) { 
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); 

    if (bitmapWorkerTask != null) { 
     final String bitmapData = bitmapWorkerTask.getFilePath(); 
     if (bitmapData != data) { 
      // Cancel previous task 
      bitmapWorkerTask.cancel(true); 
     } else { 
      // The same work is already in progress 
      return false; 
     } 
    } 
    // No task associated with the ImageView, or an existing task was cancelled 
    return true; 
} 

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { 
     if (imageView != null) { 
      final Drawable drawable = imageView.getDrawable(); 
      if (drawable instanceof AsyncDrawable) { 
       final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; 
       return asyncDrawable.getBitmapWorkerTask(); 
      } 
     } 
     return null; 
    } 

public Bitmap loadImageFromSdCard(String filePath, int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filePath, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeFile(filePath, options); 
} 

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
// Raw height and width of image 
final int height = options.outHeight; 
final int width = options.outWidth; 
int inSampleSize = 1; 

if (height > reqHeight || width > reqWidth) { 
    if (width > height) { 
     inSampleSize = Math.round((float)height/(float)reqHeight); 
    } else { 
     inSampleSize = Math.round((float)width/(float)reqWidth); 
    } 
} 
return inSampleSize;} 

class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { 

    private String mFilePath; 
    private final WeakReference<ImageView> imageViewReference; 

    public BitmapWorkerTask(ImageView imageView) { 
     // Use a WeakReference to ensure the ImageView can be garbage collected 
     imageViewReference = new WeakReference<ImageView>(imageView); 
    } 

    public String getFilePath() { 
     return mFilePath; 
    } 

    // Decode image in background. 
    @Override 
    protected Bitmap doInBackground(String... params) { 
     mFilePath = params[0];  
     final Bitmap bitmap = loadImageFromSdCard(mFilePath, 72, 72); 
     addBitmapToMemoryCache(String.valueOf(mFilePath), bitmap); 
     return bitmap; 
    } 

    // Once complete, see if ImageView is still around and set bitmap. 
    @Override 
    protected void onPostExecute(Bitmap bitmap) { 
     if (isCancelled()) { 
      bitmap = null; 
     } 

     if (imageViewReference != null && bitmap != null) { 
      final ImageView imageView = imageViewReference.get(); 
      final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); 
      if (this == bitmapWorkerTask && imageView != null) { 
       imageView.setImageBitmap(bitmap); 
      } 
     } 
    } 
} 

static class AsyncDrawable extends BitmapDrawable { 
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; 

    public AsyncDrawable(BitmapWorkerTask bitmapWorkerTask) { 
     super(); 
     bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); 
    } 

    public BitmapWorkerTask getBitmapWorkerTask() { 
     return bitmapWorkerTaskReference.get(); 
    } 
} 

// Get memory class of this device, exceeding this amount will throw an 
// OutOfMemory exception. 

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

public LruCache<String, Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 

    @Override 
    protected int sizeOf(String key, Bitmap bitmap) { 
     // The cache size will be measured in bytes rather than number of items. 
     return bitmap.getByteCount(); 
    } 
}; 

public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
    if (getBitmapFromMemCache(key) == null) { 
     mMemoryCache.put(key, bitmap); 
    } 
} 

public Bitmap getBitmapFromMemCache(String key) { 
    return mMemoryCache.get(key); 
}} 

我怎么能修理它?

UPDATE

我找到了解决办法。也许它会帮助别人。

public class ThumbnailLoader{ 
static Context context; 
int memClass = 80; 

public ThumbnailLoader(Context context) { 
    ThumbnailLoader.context = context; 
} 

public void loadBitmap(String filePath, ImageView imageView) { 
    final String imageKey = String.valueOf(filePath); 
    final Bitmap bitmap = getBitmapFromMemCache(imageKey); 
    Bitmap preloadbitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.image); 

    if (bitmap != null) { 
     imageView.setImageBitmap(bitmap); 
    }else if (cancelPotentialWork(filePath, imageView)) { 
     BitmapWorkerTask task = new BitmapWorkerTask(imageView); 
     final AsyncDrawable asyncDrawable = new AsyncDrawable(context.getResources(), preloadbitmap, task); 
     imageView.setImageDrawable(asyncDrawable); 
     task.execute(filePath); 
    } 

} 

public static boolean cancelPotentialWork(String data, ImageView imageView) { 
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); 

    if (bitmapWorkerTask != null) { 
     final String bitmapData = bitmapWorkerTask.getFilePath(); 
     if (bitmapData != data) { 
      // Cancel previous task 
      bitmapWorkerTask.cancel(true); 
     } else { 
      // The same work is already in progress 
      return false; 
     } 
    } 
    // No task associated with the ImageView, or an existing task was cancelled 
    return true; 
} 

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { 
     if (imageView != null) { 
      final Drawable drawable = imageView.getDrawable(); 
      if (drawable instanceof AsyncDrawable) { 
       final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; 
       return asyncDrawable.getBitmapWorkerTask(); 
      } 
     } 
     return null; 
    } 

public Bitmap loadImageFromSdCard(String filePath, int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filePath, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeFile(filePath, options); 
} 

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
// Raw height and width of image 
final int height = options.outHeight; 
final int width = options.outWidth; 
int inSampleSize = 1; 

if (height > reqHeight || width > reqWidth) { 
    if (width > height) { 
     inSampleSize = Math.round((float)height/(float)reqHeight); 
    } else { 
     inSampleSize = Math.round((float)width/(float)reqWidth); 
    } 
} 
return inSampleSize;} 

class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { 

    private String mFilePath; 
    private final WeakReference<ImageView> imageViewReference; 

    public BitmapWorkerTask(ImageView imageView) { 
     // Use a WeakReference to ensure the ImageView can be garbage collected 
     imageViewReference = new WeakReference<ImageView>(imageView); 
    } 

    public String getFilePath() { 
     return mFilePath; 
    } 

    // Decode image in background. 
    @Override 
    protected Bitmap doInBackground(String... params) { 
     mFilePath = params[0];  
     final Bitmap bitmap = loadImageFromSdCard(mFilePath, 68, 68); 
     addBitmapToMemoryCache(String.valueOf(mFilePath), bitmap); 
     return bitmap; 
    } 

    // Once complete, see if ImageView is still around and set bitmap. 
    @Override 
    protected void onPostExecute(Bitmap bitmap) { 
     if (isCancelled()) { 
      bitmap = null; 
     } 

     if (imageViewReference != null && bitmap != null) { 
      final ImageView imageView = imageViewReference.get(); 
      final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); 
      if (this == bitmapWorkerTask && imageView != null) { 
       imageView.setImageBitmap(bitmap); 
      } 
     } 
    } 
} 

static class AsyncDrawable extends BitmapDrawable { 
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; 

    public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { 
     super(res, bitmap); 
     bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); 
    } 

    public BitmapWorkerTask getBitmapWorkerTask() { 
     return bitmapWorkerTaskReference.get(); 
    } 
} 

final int cacheSize = 1024 * 1024 * memClass/8; 

public LruCache<String, Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 

    @Override 
    protected int sizeOf(String key, Bitmap bitmap) { 
     // The cache size will be measured in bytes rather than number of items. 
     return bitmap.getByteCount(); 
    } 
}; 

public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
    if (getBitmapFromMemCache(key) == null) { 
     mMemoryCache.put(key, bitmap); 
    } 
} 

public Bitmap getBitmapFromMemCache(String key) { 
    return mMemoryCache.get(key); 
} 
} 

这代码应该是在地方粘贴到您希望查看位图:

ThumbnailLoader tnloader = new ThumbnailLoader(getContext()); 
tnloader.loadBitmap(filepath, imageView); 
+0

感谢它帮助我很多。 – Cjames

回答

0

检查这个问题:

Lazy load of images in ListView

PS。我有几乎相同的问题,并且我记得图像只有在从网络加载后才出现 - 可能是因为缓存或其他问题。这个链接对我很有帮助。

UPDATE

您也可以存储网址在标签字段中的每个ImageView的(setteag \ gettag)。 这个教程你可以找到here

+0

谢谢,我已经看到了这个问题,即使我试图用LazyList更改一部分代码来从sdcard加载图像,但我遇到了同样的问题。 – kormateusz

+1

我记得,你也必须为你的视图设置标签(view.setTag)和你想要加载到你的imageView的url,当你加载它时,你必须检查这个标签和你下载的东西。 – dilix

+1

要了解我的意思,您可以查看此链接:http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/ – dilix