在网格视图中显示图像的最佳方法是滚动平滑

首先,我已经做了很少的事情来在gridview中显示图像,使滚动时变得平滑

1.从后台线程上加载来自互联网的图像

AsyncTask acyncTask ; HandlerThread handlerThread ; URL imageUrl = new URL(link);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is=conn.getInputStream(); final Bitmap bitmap = BitmapFactory.decodeStream(is);

2.将位图设置为样本大小以节省内存

 final BitmapFactory.Options option = new BitmapFactory.Options(); option.inJustDecodeBounds = true; BitmapFactory.decodeFile(mFile.getPath(), option); option.inSampleSize = calculateInSampleSize(option , mSize , mSize); option.inJustDecodeBounds = false; option.inPurgeable = true ; option.inDither = false ; option.inScaled = false ; option.inPreferredConfig = Bitmap.Config.ARGB_8888; 

3.制作缓存以保存解码的位图

 LruCache lruCache = new LruCache(); 

baseadapter getView(); 我将lruCache.get(key)取得解码后的位图

4.通过处理程序解码位图时的延迟加载

  Handler handler = new Handler(); handler.post(new Runnable(){ public void run(){ imageView.setimageBitmap(bitmap); } }); 

现在我面临一个大问题,当我滚动时它仍然有点滞后我有谷歌关于某些东西可以使滚动更好 ,不知道真的有什么可以提高或问题是从我检查每个问题出来getView()只花了我大约2~6ms ,它会调用我的代码异步加载图像表单工作线程 ,所以我真的不知道为什么有些应用程序可以加载非常流畅 ? 我的情况是当滚动屏幕看起来不是很顺利是否有一些建议可以适用?

编辑:当我滚动时,在缓存中find位图并在屏幕上显示,如果我快速滚动,它看起来就像没有滚动到足以显示图像,它会使我的滚动不那么顺利,即使我有缓存下来缓存中的位图

这是适配器代码:

 if (convertView == null) { convertView = layoutInflater.inflate( R.layout.row_display_image_grid, null); viewHolder = new DisplayImageGridViewHolder(); viewHolder.background = (RelativeLayout) convertView .findViewById(R.id.background); viewHolder.image = (ImageView) convertView.findViewById(R.id.image); viewHolder.text = (TextView) convertView.findViewById(R.id.text); viewHolder.position = position; viewHolder.text.setEllipsize(TruncateAt.END); viewHolder.text.setTypeface(typeFace); viewHolder.image.setOnClickListener(this); viewHolder.image.setOnLongClickListener(this); convertView.setTag(viewHolder); } else { viewHolder = (DisplayImageGridViewHolder) convertView.getTag(); } viewHolder.position = position; imageLoader.loadImage(imageLinkList.get(position), viewHolder.image); return convertView; 

下面是我使用的LazyLoader的示例。 注意我使用SoftReferences作为位图,现在使用LruCache可以更好地服务。

这将从web / sdcard / memory异步加载图像,并从占位符图像创建淡入效果。

 public class ImageLoader { private static MemoryCacheNew memoryCache=new MemoryCacheNew(); private static FileCache fileCache; private static BitmapFactory.Options bitmapOptions; private static int mInSampleSize; public ImageLoader(Context context, int inSampleSize){ fileCache=new FileCache(context); context = null; bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = mInSampleSize = inSampleSize; bitmapOptions.inPreferredConfig = Config.RGB_565; bitmapOptions.inInputShareable = true; bitmapOptions.inDither = false; } final static int PLACEHOLDER_IMAGE = R.drawable.store_placeholder; public void DisplayImage(String url, ImageView imageView, boolean checkTags){ try{ new AsyncPhotoTask(imageView, url, checkTags).execute(); }catch(Exception e){ e.printStackTrace(); } } public void DisplayImage(String url, ImageView imageView) { DisplayImage(url, imageView, true); } private static Bitmap getBitmap(String url) { File f=fileCache.getFile(url); if(f!= null){ //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; } //from web try { Bitmap bitmap=null; URL imageUrl; imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); InputStream is=conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); is.close(); os.close(); bitmap = decodeFile(f); return bitmap; } catch (Exception ex){ ex.printStackTrace(); return null; } } //decodes image and scales it to reduce memory consumption private static Bitmap decodeFile(File f){ try { return BitmapFactory.decodeStream(new FileInputStream(f), null, bitmapOptions); } catch (FileNotFoundException e) { } catch (OutOfMemoryError err){ System.gc(); } return null; } private static class AsyncPhotoLoad extends AsyncTask{ private Bitmap bmp; private ImageView imageView; private String url; private boolean checkTags; public AsyncPhotoLoad(ImageView imageView, String url, boolean checkTags ){ this.imageView = imageView; this.url = url; this.checkTags = checkTags; } @Override protected TransitionDrawable doInBackground(Void... arg0) { //check that this is the correct imageview TransitionDrawable transition = null; try{ if(checkTags){ String tag = (String)imageView.getTag(); if(!tag.equals(url)) return null; } bmp = getBitmap(url); if(bmp != null){ memoryCache.put(url, bmp, mInSampleSize); Drawable oldDrawable = imageView.getDrawable(); if(!(oldDrawable instanceof TransitionDrawable)){ Drawable layers[] = new Drawable[2]; layers[0] = imageView.getDrawable(); layers[1] = new BitmapDrawable(bmp); transition = new TransitionDrawable(layers); } } }catch(Exception e){ e.printStackTrace(); } return transition; } @Override protected void onPostExecute(TransitionDrawable result) { if(result != null){ try{ if(checkTags){ String tag = (String)imageView.getTag(); if(!tag.equals(url)){ return; } } imageView.setImageDrawable(result); result.startTransition(300); } catch(Exception e){ e.printStackTrace(); } } else { if(checkTags){ try{ String tag = (String)imageView.getTag(); if(!tag.equals(url)) return; }catch(Exception e){ e.printStackTrace(); } } } } } private static class AsyncPhotoTask extends AsyncTask{ private ImageView imageView; private String url; private boolean checkTags; public AsyncPhotoTask(ImageView imageView, String url, boolean checkTags){ this.imageView = imageView; this.url = url; this.checkTags = checkTags; } @Override protected Bitmap doInBackground(Void... params) { try{ if(checkTags) imageView.setTag(url); }catch(Exception e){ e.printStackTrace(); } return memoryCache.get(url, mInSampleSize); } @Override protected void onPostExecute(Bitmap result) { try{ if(result!=null && !result.isRecycled()){ imageView.setImageBitmap(result); } else { imageView.setImageResource(PLACEHOLDER_IMAGE); new AsyncPhotoLoad(imageView, url, checkTags).execute(); } }catch(Exception e){ e.printStackTrace(); } } } public static void clearCache() { memoryCache.clear(); fileCache.clear(); } public static void clearMemory(){ memoryCache.clear(); } public static class MemoryCacheNew { private HashMap cache=new HashMap(); public Bitmap get(String id, int sampleSize){ if(!cache.containsKey(id)) return null; if(cache.get(id) == null) return null; if(cache.get(id).sampleSize != sampleSize) return null; SoftReference ref = cache.get(id).softBitmap; return ref.get(); } public void put(String id, Bitmap bitmap, int sampleSize){ cache.put(id, new CachedBitmap(bitmap, sampleSize)); } public void clear() { cache.clear(); } private static class CachedBitmap { public SoftReference softBitmap; public int sampleSize; public CachedBitmap(Bitmap bitmap, int sampleSize){ this.softBitmap = new SoftReference(bitmap); this.sampleSize = sampleSize; } } } } public class FileCache { private File cacheDir; public FileCache(Context context){ //Find the dir to save cached images if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) cacheDir=new File(context.getExternalCacheDir(),Consts.STORE_CACHE); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } public File getFile(String url){ //I identify images by hashcode. Not a perfect solution, good for the demo. String filename=String.valueOf(url.hashCode()); File f = new File(cacheDir, filename); return f; } public void clear(){ File[] files=cacheDir.listFiles(); for(File f:files) f.delete(); } } 

你这样称呼它:

 imageLoader.DisplayImage(url, holder.image); 

尽量确保每个位图的尺寸最佳……它们应该与容器的大小相当。 在通过RemoteView发送它们之前,尽可能地缩小它们。 您可以使用onAppWidgetOptionsChanged计算窗口小部件的大小。

此外,尝试使用setImageViewUri(使用内容提供程序)而不是setImageViewBitmap以获得最佳性能。