2083

我正在使用列表视图显示与这些图像关联的一些图像和标题。我正在从互联网上获取图像。有没有一种方法可以延迟加载图像,以便在显示文本时,UI不会被阻止,图像会在下载时显示?

图像总数不固定。

6

41个答案41

重置为默认值
1152

以下是我创建的内容,用于保存我的应用程序当前显示的图像。请注意,这里使用的“Log”对象是我在Android中围绕最终Log类的自定义包装器。

软件包com.wilson.android.library;/*根据一项或多项授权给Apache Software Foundation(ASF)贡献者许可协议。请参阅NOTICE文件与此工作一起分发以获取更多信息关于版权所有权。ASF许可此文件根据Apache许可证2.0版(“许可证”);除非符合规定,否则您不能使用此文件使用许可证。您可以在以下地址获得许可证副本:http://www.apache.org/licenses/LICENSE-2.0除非适用法律要求或书面同意,根据许可证分发的软件在“按原样”,无任何保证或条件KIND,明示或暗示。请参阅许可证管理权限和限制的特定语言根据许可证。*/导入java.io.IOException;公共类DrawableManager{私有最终Map<String,Drawable>drawableMap;公共DrawableManager(){drawableMap=新的HashMap<String,Drawable>();}public Drawable fetchDrawable(String urlString){if(drawableMap.containsKey(urlString)){return drawableMap.get(urlString);}Log.d(this.getClass().getSimpleName(),“图片url:”+urlString);尝试{InputStream is=获取(urlString);Drawable Drawable=Drawable.createFromStream(is,“src”);if(可提取!=空){drawableMap.put(urlString,drawable);Log.d(this.getClass().getSimpleName()),“得到了一个可绘制的缩略图:”+drawable.getBounds()+“,”+drawable.getIntrinsic高度()+“,”+drawable.getIntrinsic宽度()+”,“+drawable.getMinimumHeight()+“,”+drawable.getMinimumWidth());}其他{Log.w(this.getClass().getSimpleName(),“无法获取缩略图”);}可回收;}catch(MalformedURLE异常e){Log.e(this.getClass().getSimpleName(),“fetchDrawable失败”,e);返回null;}捕获(IOException e){Log.e(this.getClass().getSimpleName(),“fetchDrawable失败”,e);返回null;}}public void fetchDrawableOnThread(final String urlString,final ImageView ImageView){if(drawableMap.containsKey(urlString)){imageView.setImageDrawable(drawableMap.get(urlString));}最终处理程序处理程序=新处理程序(Looper.getMainLooper()){@覆盖public void handleMessage(消息消息){imageView.setImageDrawable((可绘制)消息.obj);}};线程=新线程(){@覆盖公共void run(){//TODO:将imageView设置为“挂起”图像Drawable Drawable=fetchDrawable(urlString);消息消息=handler.obtainMessage(1,可绘制);handler.sendMessage(消息);}};thread.start();}私有InputStream获取(String urlString)引发MalformedURLException、IOException{DefaultHttpClient httpClient=新的DefaultHtt客户端();HttpGet请求=新的HttpGet(urlString);HttpResponse响应=httpClient.execute(request);return response.getEntity().getContent();}}
11
  • 110
    我认为您应该使用SoftReferences,这样您的程序就不会导致OutOfMemoryException。由于GC可以在堆大小增加时清除软引用。。。你可以管理你自己的一代,比如几秒钟后你可以把你的图像放在那个列表中,在加载之前,你应该检查图像是否存在,然后不要再下载它,而是从那个列表中收集它,并把它放回你的softref列表,过些时候你可以清除你的硬列表:) 评论 2011年1月18日8:08
  • 41
    谷歌货架项目是一个很好的例子,看看他们是如何做到的code.google.com/p/shelves 评论 2011年1月18日8:09
  • 14
    当drawableMap包含图像时,您不会错过返回。。。不启动提取线程? 评论 2011年3月29日22:06
  • 7
    此代码有几个问题。首先,您应该缓存Drawables,这将导致内存泄漏:stackoverflow.com/questions/7648740/…其次,缓存本身从未被清除,因此它将永远增长,这是另一个内存泄漏。 评论 2011年11月15日5:35
  • 12
    没有人听说过LRU缓存 developer.android.com/training/displaying-bitmaps/… 评论 2013年5月28日7:26
1052

我做的懒惰列表的简单演示(位于GitHub),带有图像。

基本用法

ImageLoader ImageLoader=新ImageLoad(上下文)。。。imageLoader。显示图像(url,imageView);

别忘了添加对您的AndroidManifest.xml具有以下权限:

<uses-permission android:name=“android.permission.INTERNET”/><uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/>请

只创建一个ImageLoader实例并在您的应用程序。这样图像缓存将更加高效。

它可能对某人有所帮助。它在后台线程中下载图像。图像缓存在SD卡和内存中。缓存实现非常简单,对于演示来说已经足够了。我使用inSampleSize解码图像以减少内存消耗。我还尝试正确处理回收的视图。

替代文字

0
565

我推荐开源工具通用图像加载器它最初基于Fedor Vlasov的项目LazyList(懒惰列表)从那以后,情况有了很大改善。

  • 多线程图像加载
  • 可以广泛调整ImageLoader的配置(线程执行器、下载器、解码器、内存和磁盘缓存、显示图像选项等)
  • 可以在内存和/或设备的文件系统(或SD卡)上缓存图像
  • “监听”加载过程的可能性
  • 可以使用单独的选项自定义每次显示图像调用
  • 小工具支持
  • Android 2.0+支持

0
166

多线程提高性能Gilles Debunne的教程。

这是来自Android开发者博客。建议的代码使用:

  • 异步任务.
  • 一个硬的,有限的尺寸,FIFO缓存.
  • 柔软,容易垃圾收集站-ed缓存。
  • 占位符 可提取下载时。

在此处输入图像描述

5
  • 11
    它在2.1中也很好用。只是不要使用AndroidHttpClient。 评论 2011年2月5日2:22
  • @thomas-ahle谢谢,我看到AndroidHttpClient在2.1中给出了错误,因为它是从2.2实现的,但并没有真正尝试找到其他东西来替换它。 评论 2011年2月9日8:02
  • 5
    @阿迪娜你说得对,我忘了。然而,食谱中没有什么是不能用普通HttpClient完成的。 评论 2011年2月22日12:49
  • 我在好几个地方都听说过,谷歌不推荐软引用,因为与系统的早期版本相比,android内核非常渴望收集这些引用。 评论 2014年5月26日7:46
  • 你能帮忙吗?stackoverflow.com/questions/62624070/… 评论 2020年6月28日17:04
118

更新:请注意,这个答案现在非常无效。垃圾收集器对SoftReference和WeakReference采取积极的行动,因此此代码不适用于新应用程序。(相反,可以尝试以下库通用图像加载器在其他答案中建议。)

感谢James提供的代码,以及Bao-Long建议使用SoftReference。我对James的代码进行了SoftReference更改。不幸的是,SoftReferences导致我的图像被垃圾收集得太快。在我的例子中,没有SoftReference就可以了,因为我的列表大小有限,而且我的图像很小。

一年前,有一次关于谷歌群组上的SoftReferences的讨论:链接到线程。作为过早垃圾收集的解决方案,他们建议使用dalvik.system手动设置VM堆大小。VMRuntime.setMinimumHeapSize(),这对我来说不是很有吸引力。

公共DrawableManager(){drawableMap=新的HashMap<String,SoftReference<Drawable>>();}public Drawable fetchDrawable(String urlString){SoftReference<Drawable>drawableRef=drawableMap.get(urlString);if(drawableRef!=空){Drawable Drawable=drawableRef.get();if(可提取!=空)可回收;//引用已过期,请从drawableMap中删除密钥drawableMap.remove(urlString);}if(Constants.LOGGING)Log.d(this.getClass().getSimpleName(),“图像url:”+urlString);尝试{InputStream is=获取(urlString);Drawable Drawable=Drawable.createFromStream(is,“src”);drawableRef=新SoftReference<Drawable>(Drawable);drawableMap.put(urlString,drawableRef);if(Constants.LOGGING)Log.d(this.getClass().getSimpleName()),“获取缩略图可绘制:”+drawable.getBounds()+“,”+drawable.getIntrinsic高度()+“,”+drawable.getIntrinsic宽度()+”,“+drawable.getMinimumHeight()+“,”+drawable.getMinimumWidth());return drawableRef.get();}catch(MalformedURLE异常e){if(Constants.LOGGING)Log.e(this.getClass().getSimpleName(),“fetchDrawable failed”,e);返回null;}捕获(IOException e){if(Constants.LOGGING)Log.e(this.getClass().getSimpleName(),“fetchDrawable failed”,e);返回null;}}public void fetchDrawableOnThread(final String urlString,final ImageView ImageView){SoftReference<Drawable>drawableRef=drawableMap.get(urlString);if(drawableRef!=空){Drawable Drawable=drawableRef.get();if(可提取!=空){imageView.setImageDrawable(drawableRef.get());回报;}//引用已过期,请从drawableMap中删除密钥drawableMap.remove(urlString);}最终处理程序处理程序=新处理程序(){@覆盖public void handleMessage(消息消息){imageView.setImageDrawable((可绘制)消息.obj);}};线程=新线程(){@覆盖公共void run(){//TODO:将imageView设置为“挂起”图像Drawable Drawable=fetchDrawable(urlString);消息消息=handler.obtainMessage(1,可绘制);handler.sendMessage(消息);}};thread.start();}
4
  • 4
    您可以创建硬世代和软世代。你可以修复一个时间清零缓存,它将在3秒内清除所有未被访问的图像。你可以看看谷歌货架项目 评论 2011年1月18日8:06
  • developer.android.com/reference/java/lang/ref/…SoftReference文档中有一条关于缓存的注释,请参阅“避免缓存软引用”一节。大多数应用程序都应该使用android.util。LruCache而不是软引用。 评论 2013年2月26日11:48
  • 我很欣赏你的代码,但现在在新的Android O/S中,有“积极”的垃圾收集。持有弱引用对我来说没有任何意义。 评论 2013年7月21日17:54
  • @j2emanue你说得对,正如我试图在我的答案顶部指出的那样,SoftReferences被垃圾收集得太快了。我会尝试编辑这个答案,使其更加清晰。
    – 少说话
    评论 2013年7月22日0:13
108

毕加索

使用杰克·沃顿的毕加索图书馆。(ActionBarSherlock开发者的完美图像加载库)

一个功能强大的Android图像下载和缓存库。

图像为Android应用程序添加了急需的上下文和视觉效果。毕加索只需一行代码就可以在应用程序中轻松加载图像!

毕加索(上下文).load(“http://i.imgur.com/DvpvklR.png“).转换为(imageView);

在Android上加载图像的许多常见陷阱都是由毕加索自动处理的:

在适配器中处理ImageView回收和下载取消。使用最少内存的复杂图像转换。自动内存和磁盘缓存。

毕加索·杰克·沃顿图书馆

滑翔机

Glide是一个快速高效的Android开源媒体管理框架,它将媒体解码、内存和磁盘缓存以及资源池封装到一个简单易用的界面中。

Glide支持提取、解码和显示视频静态图像、图像和动画GIF。Glide包含一个灵活的API,允许开发人员插入几乎任何网络堆栈。默认情况下,Glide使用一个基于自定义HttpUrlConnection的堆栈,但也包括谷歌Volley项目的实用程序库插件或Square的OkHttp库。

使用(this).load(“your-url-here”).into(imageView);

Glide的主要关注点是使滚动任何类型的图像列表尽可能平滑和快速,但Glide对于几乎任何需要获取、调整大小和显示远程图像的情况都是有效的。

滑翔图像加载库

脸书壁画

Fresco是一个在Android应用程序中显示图像的强大系统。

Fresco负责图像加载和显示,所以您不必这样做。它将从网络、本地存储或本地资源加载图像,并显示占位符,直到图像到达。它有两个级别的缓存;一个在内存中,另一个在内部存储器中。

湿壁画Github

在Android 4.x及更低版本中,Fresco将图像放在Android内存的一个特殊区域。这样可以让应用程序运行得更快,并且很少出现可怕的OutOfMemoryError。

Fresco文件

1
  • 1
    毕加索是由Square开发的图书馆 评论 2018年5月16日21:03
88

高性能装载机-在检查了这里建议的方法后,我用过本氏溶液有一些变化-

  1. 我意识到使用drawable比使用位图更快,所以我使用drawab

  2. 使用SoftReference很好,但它会使缓存的图像被频繁删除,所以我添加了一个包含图像引用的链接列表,防止图像被删除,直到达到预定义的大小

  3. 为了打开InputStream,我使用了java.net。URLConnection允许我使用web缓存(您需要先设置响应缓存,但这是另一回事)

我的代码:

导入java.util。地图;导入java.util。HashMap;导入java.util。链接列表;导入java.util。收藏;导入java.util。WeakHashMap;导入java.lang.ref.SoftReference;导入java.util.concurrent。执行人;导入java.util.concurrent。执行服务;导入android.graphics.drawable。可提取;导入android.widget。ImageView;导入android.os。经办人;导入android.os。消息;导入java.io.InputStream;导入java.net。畸形URL异常;导入java.io.IOException;导入java.net。URL;导入java.net。URL连接;公共类DrawableBackgroundDownloader{private final Map<String,SoftReference<Drawable>>mCache=new HashMap<String,软引用<Drawable>>();private final LinkedList<Drawable>mChacheController=新LinkedList<Drawable>();私有ExecutorService mThreadPool;private final Map<ImageView,String>mImageViews=Collections.synchronizedMap(new WeakHashMap<ImageView,String>());公共静态int MAX_CACHE_SIZE=80;public int THREAD_POOL_SIZE=3;/***施工单位*/公共DrawableBackgroundDownloader(){mThreadPool=Executors.newFixedThreadPool(THREAD_POOL_SIZE);}  /***清除所有实例数据并停止运行线程*/public void重置(){ExecutorService旧线程池=mThreadPool;mThreadPool=Executors.newFixedThreadPool(THREAD_POOL_SIZE);oldThreadPool.shutdownNow();mChacheController.clear();mCache.clear();mImageViews.clear();}  public void loadDrawable(最终String url,最终ImageView ImageView,Drawable占位符){mImageViews.put(图像视图,url);可绘制可绘制=getDrawableFromCache(url);//签入UI线程,因此没有并发问题if(drawable!=null){//Log.d(空,“从mCache加载的项:”+url);imageView.setImageDrawable(可绘制);}其他{imageView.setImageDrawable(占位符);queueJob(url、imageView、占位符);}  } private Drawable getDrawableFromCache(字符串url){if(mCache.containsKey(url)){返回mCache.get(url).get();}  返回null;}私有同步void putDrawableInCache(String url,Drawable Drawable){int chacheControllerSize=mChacheControll.size();if(chacheControllerSize>MAX_CACHE_SIZE)mChacheController.subList(0,MAX_CACHE_SIZE/2).clear();mChacheController.addLast(可绘制);mCache.put(url,新SoftReference<Drawable>(Drawable));}  private void queueJob(最终String url,最终ImageView ImageView,最终Drawable占位符){/*在UI线程中创建处理程序。*/final Handler处理程序=new Handler(){@覆盖public void handleMessage(消息消息){字符串标记=mImageViews.get(imageView);if(标记!=空&&tag.equals(url)){if(imageView.isShown())if(msg.obj!=空){imageView.setImageDrawable(可绘制)msg.obj);}其他{imageView.setImageDrawable(占位符);//Log.d(null,“fail”+url);} }  }  };  mThreadPool.submit(新的Runnable(){@覆盖公共void run(){final Drawable bmp=downloadDrawable(url);//如果视图不再可见,则图像将在缓存中准备好下次使用if(imageView.isShown()){消息消息=Message.obtain();message.obj=bmp;//Log.d(空,“下载的项目:”+url);handler.sendMessage(消息);}}  });  }  private Drawable downloadDrawable(字符串url){尝试{InputStream为=getInputStream(url);Drawable Drawable=Drawable.createFromStream(is,url);putDrawableInCache(url,drawable);可回收;}catch(MalformedURLException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}  返回null;}  私有输入流getInputStream(String urlString)引发MalformedURLException、IOException{URL URL=新URL(urlString);URL连接连接;连接=url.openConnection();connection.setUseCaches(true);connection.connect();输入流响应=connection.getInputStream();返回响应;}}
10
  • 效果很好!顺便说一句,类名中有一个拼写错误。
    – 穆林斯
    评论 2011年12月7日14:25
  • 6
    如果这样可以节省其他人的时间:导入java.util。地图;导入java.util。HashMap;导入java.util。链接列表;导入java.util。收藏;导入java.util。WeakHashMap;导入java.lang.ref.SoftReference;导入java.util.concurrent。执行人;导入java.util.concurrent。执行服务;导入android.graphics.drawable。可提取;导入android.widget。ImageView;导入android.os。经办人;导入android.os。消息;导入java.io.InputStream;导入java.net。畸形URL异常;导入java.io.IOException;导入java.net。URL;导入java.net。URL连接; 评论 2012年1月8日5:01
  • 非常感谢,这是一个很好的实现。我还为加载drawable时放置了一个不同的占位符,以便用户可以获得一些反馈。 评论 2012年2月7日15:53
  • 此外,我认为最好在executorService(mThreadPool)中使用后进先出队列,而不是默认的FIFO,以便首先加载最后请求的图像(可能是可见的图像)。请参见stackoverflow.com/questions/4620061/how-to-create-lifo-executor(如何创建lifo-executor) 评论 2012年2月7日16:19
  • 10
    @MichaelReed,如果您是Eclipse用户,我建议您使用Ctrl-Shift-O(这是字母O,而不是数字0)。它自动化了添加导入的过程并为您组织它们。如果您在Mac上,请使用Command-Shift-O。 评论 2012年3月20日15:21
82

我一直在关注这个Android培训,我认为它在下载图像方面做得很好,而且不会阻塞主UI。它还处理缓存和滚动许多图像的处理:高效加载大位图

2
  • 很抱歉,我只指向了谷歌IO应用程序的一个类(我已经来不及编辑了)。您应该认真研究它们的所有图像加载和缓存实用程序类,这些类可以在与缓存类相同的包.
    – 姆奎奇
    评论 2013年1月31日5:28
  • 有人建议从iosched应用程序的util文件夹中获取DiskLruCache、Image*.java文件,以帮助处理列表视图的图像加载/缓存吗?我的意思是,绝对值得遵循在线开发人员指南中关于这个主题的内容,但这些类(来自iosched)在这个模式上走得更远了一点。
    – 高塔姆
    评论 2013年4月25日16:58
73

1 毕加索允许在应用程序中轻松加载图像,通常只需一行代码!

使用渐变:

实现“com.squareup.picasso:picasso:(插入最新版本)”

只有一行代码!

毕加索.get().load(“http://i.imgur.com/DvpvklR.png“).转换为(imageView);

2 滑翔机Android的图像加载和缓存库专注于平滑滚动

使用渐变:

存储库{mavenCentral()谷歌()}依赖关系{实现“com.github.bumptech.glide:glide:4.11.0”annotationProcessor“com.github.bumptech.glide:编译器:4.11.0”}

//对于简单视图:

带(this).load(“http://i.imgur.com/DvpvklR.png“).转换为(imageView);

三。 壁画是一个在Android中显示图像的强大系统应用。Fresco负责图像加载和显示,因此您没有至。

壁画入门

1
56

我写了一个教程,解释如何在列表视图中延迟加载图像。我将详细介绍回收和并发问题。我还使用固定线程池来防止生成大量线程。

Listview教程中图像的延迟加载

46

我这样做的方法是启动一个线程,在后台下载图像,并为每个列表项传递一个回调。图像下载完成后,它会调用回调来更新列表项的视图。

然而,当您回收视图时,这种方法并不能很好地工作。

4
  • 对每个图像使用线程也是我使用的方法。如果将模型与视图分离,则可以将模型持久化到“活动”之外(如“应用程序”类中),以保持它们的缓存。如果您有许多图像,请注意资源不足。 评论 2009年2月15日0:40
  • 你能详细说明一下吗。我是机器人开发新手。不过谢谢你的提示 评论 2009年2月15日14:23
  • 14
    为每个图像启动一个新线程并不是一个有效的解决方案。您可能会在内存中出现大量线程,并冻结UI。
    – 费多尔
    评论 2010年7月1日0:04
  • Fedor同意,我通常使用队列和线程池,这是我使用的最佳方式。 评论 2010年7月4日22:48
36

我只想再举一个好例子,XML适配器。由于它是由谷歌使用的,我也使用相同的逻辑来避免OutOfMemory错误。

基本上此ImageDownloader是您的答案(因为它涵盖了您的大多数需求)。有些还可以在其中实现。

1
33

这是安卓系统上的一个常见问题,许多人已经通过多种方式解决了这个问题。在我看来,我看到的最好的解决方案是相对较新的库毕加索。以下是亮点:

  • 开源,但由杰克·沃顿属于ActionBarSherlock公司名声。
  • 使用一行代码从网络或应用程序资源异步加载图像
  • 自动列表视图侦查
  • 自动磁盘和内存缓存
  • 可以进行自定义转换
  • 许多可配置选项
  • 超简单API
  • 经常更新
0
33

我一直在使用新安卓排球库中的NetworkImageViewcom.android.volley.toolbox。网络图像视图,它似乎运行得很好。显然,这与谷歌游戏和其他新的谷歌应用程序。绝对值得一看。

1
  • 2
    我认为这是最好的解决方案-其他答案都很古老-凌空截击真的很快,并且结合了jake warthons disklrucache,这是一个很好的解决方案–我尝试了很多其他的解决方案,但没有一个能像凌空截杀那样稳定快速 评论 2014年9月7日22:19
29

嗯,从互联网上下载图像有很多解决方案。你也可以使用图书馆Android查询。它将为您提供所有必需的活动。确保你想做什么,并阅读图书馆维基页面。并解决了图像加载限制。

这是我的代码:

@覆盖public View getView(int position,View convertView,ViewGroup parent){视图v=convertView;如果(v==空){LayoutInfluer vi=(LayoutINfluer)getSystemService(Context.LAYOUT_INFLATER_SERVICE);v=vi.inflate(R.layout.row,空);}ImageView ImageView=(ImageView)v.findViewById(R.id.icon);AQuery aq=新AQuery(convertView);字符串imageUrl=“http://www.vikispot.com/z/images/vikisport/android-w.png";aq.id(imageview).progress(this).image(imageUrl,真,真,0,0,新位图AjaxCallback(){@覆盖公共void回调(String url、ImageView iv、Bitmap bm、AjaxStatus状态){iv.setImageBitmap(bm);}));返回v;}

它应该能解决你的懒惰加载问题。

1
27

我认为这个问题在Android开发人员中非常流行,有很多这样的库声称可以解决这个问题,但只有少数看起来符合要求。AQuery公司是这样一个库,但它在各个方面都比大多数库要好,值得一试。

23

你必须尝试这个通用加载器是最好的。我在做了很多延迟加载的RnD之后使用了这个。

通用图像加载器

特征

  • 多线程图像加载(异步或同步)
  • ImageLoader配置的广泛定制(线程执行器、下载器、解码器、内存和磁盘缓存、显示图像选项等)
  • 每个显示图像调用都有许多自定义选项(存根图像、缓存开关、解码选项、位图处理和显示等)
  • 内存和/或磁盘上的图像缓存(设备的文件系统或SD卡)
  • 监听加载过程(包括下载进度)

Android 2.0+支持

在此处输入图像描述

22

看看吧百叶窗插件,Appledium的轻量级SDWebImage(iOS上的一个不错的库)到Android的端口。它支持异步缓存,存储失败的URL,很好地处理并发,并包含有用的子类。

也欢迎Pull请求(和错误报告)!

18

Droid部件图像获取器这需要零配置才能开始。

  • 使用内存中的磁盘(&I)最近最少使用(LRU)缓存。
  • 有效地解码图像。
  • 支持在后台线程中修改位图。
  • 具有简单的交叉渐变。
  • 具有图像加载进度回调。

克隆Droid部件Gram例如:

在此处输入图像描述

1
17

Novoda也有一个很棒的惰性图像加载库Songkick、Podio、SecretDJ和ImageSearch等许多应用程序都使用它们的库。

他们的图书馆是托管的在这里在Github上,他们有一个非常活跃的问题跟踪器也。他们的项目似乎也相当活跃,在撰写此回复时提交了300多个。

1
  • 2
    实际上诺沃达是一个很棒的图书馆,但是。。。有时你不需要一个庞大的库,只需要一个简单的解决方案。这就是为什么Github中的LazyList如此出色的原因,如果你的应用程序只在listView中显示一个图像,而不是你应用程序的主要功能,那只是我更喜欢使用更轻量级的活动。否则,如果你知道你必须经常使用,并且是核心的一部分,请尝试Novoda。 评论 2013年4月15日15:34
17

对于那些犹豫不决要使用哪个库来加载懒惰的图像的人来说,这只是一个快速提示:

有四种基本方法。

  1. DIY=>不是最好的解决方案,但对于一些图像,如果您想避免使用其他库的麻烦

  2. 排球的懒惰加载库=>来自android的玩家。它很好,而且所有东西都记录得很差,因此使用起来很困难。

  3. 毕加索:一个简单可行的解决方案,你甚至可以指定你想要引入的确切图像大小。它使用起来很简单,但对于需要处理大量图像的应用程序来说,可能不是很“高效”。

  4. UIL:延迟加载图像的最佳方式。您可以缓存图像(当然需要权限),初始化加载程序一次,然后完成工作。迄今为止我见过的最成熟的异步映像加载库。

16

如果你想像Facebook一样显示Shimmer布局,有一个官方的Facebook库。FaceBook闪屏安卓

它解决了所有问题,您只需将所需的设计代码以嵌套方式放入微光框架中。这是一个示例代码。

<com.facebook.shimmer。垫片框架布局android:id=“@+id/simmer_view_container”android:layout_width=“wrap_content”android:layout_height=“wrap_content”微光:持续时间=“1000”><这里将显示您的内容/></com.facebook.shimmer。垫片框架布局>

这是它的java代码。

ShimmerFrameLayout shimmerContainer=(ShimmerFrameworkLayout)findViewById(R.id.shimmer_view_container);shimmerContainer.startShimmerAnimation();

在渐变文件中添加此依赖项。

实现'com.facebook.shimmer:shimmer:0.1.0@aar'

这是它的样子。闪亮的Android屏幕截图

15

检查我的叉子LazyList(懒惰列表)。基本上,我通过延迟调用ImageView来改进LazyList,并创建了两个方法:

  1. 当您需要输入“正在加载图像…”之类的内容时
  2. 当您需要显示下载的图像时。

我还通过实现单子在此对象中。

12

以上所有代码都有自己的价值,但根据我的个人经验,请尝试毕加索。

毕加索是专门用于此目的的库,实际上它将自动管理缓存和所有其他网络操作。您必须在项目中添加库,只需编写一行代码即可从远程URL加载图像。

请访问此处:http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso-cms-22149

11

使用滑动库。它对我有效,对你的代码也有效。它既适用于图像,也适用于gif。

ImageView ImageView=(ImageView)findViewById(R.id.test_image);GlideDrawableImageViewTarget imagePreview=新的GlideDrafableImageView目标(imageView);滑翔机.带(这个).load(url).listener(新的RequestListener<String,GlideDrawable>(){@覆盖public boolean onException(异常e,字符串模型,目标<GlideDrawable>目标,boolean isFirstResource){返回false;}@覆盖public boolean onResourceReady(GlideDrawable资源,字符串模型,Target<GlideDrafable>Target,boolean isFromMemoryCache,booleans isFirstResource){返回false;}}).into(图像预览);}
8

我可以推荐另一种很有魅力的方式:Android Query。

你可以下载1月文件来自在这里

AQuery androidAQuery=新AQuery(this);

例如:

androidAQuery.id(您的IMAGEVIEW).image(您要加载的图像,true,true、getDeviceWidth(),您想要显示的任何默认图像);

它非常快速准确,使用它,您可以找到更多功能,如加载时的动画、获取位图(如果需要)等。

0
8

给予采水场一次尝试。它有非常简单的方法来异步加载和缓存图像。

7

URLImageViewHelper是一个很棒的库,可以帮助您做到这一点。

5
公共类ImageDownloader{Map<String,Bitmap>imageCache;公共ImageDownloader(){imageCache=新HashMap<字符串,位图>();}//下载功能公共void下载(String url,ImageView ImageView){if(cancelPotentialDownload(url,imageView)){//在此处缓存代码String filename=String.valueOf(url.hashCode());文件f=新文件(getCacheDirectory(imageView.getContext()),文件名);//位图在内存缓存中吗?位图位图=空;bitmap=(位图)imageCache.get(f.getPath());if(位图==空){bitmap=BitmapFactory.decodeFile(f.getPath());if(位图!=空){imageCache.put(f.getPath(),位图);}}//没有?下载它if(位图==空){尝试{BitmapDownloaderTask任务=新的Bitmap Downloader任务(图像视图);DownloadedDrawable DownloadedDrawable=新下载的Drawable(任务);imageView.setImageDrawable(已下载的Drawable);task.execute(url);}catch(异常e){Log.e(“错误==>”,e.toString());}}其他{//是吗?设置图像imageView.setImageBitmap(位图);}}}//取消下载(仅限内部)private static boolean cancelPotentialDownload(字符串url,图像视图图像视图){BitmapDownloaderTask bitmapDonloaderTask=获取位图下载程序任务(图像视图);if(bitmapDownloaderTask!=空){字符串bitmapUrl=bitmapDownloaderTask.url;if((bitmapUrl==null)||(!bitmapUrl.equals(url)){bitmapDownloaderTask.cancel(true);}其他{//已在下载相同的URL。返回false;}}返回true;}//如果imageview已有下载,则获取现有下载专用静态位图下载程序任务getBitmapDownloaderTask(图像视图图像视图){if(imageView!=空){Drawable Drawable=imageView.getDrawable();if(DownloadedDrawable的drawable实例){DownloadedDrawable DownloadedDrawable=(Downloaded drawable)drawable;return downloadedDrawable.getBitmapDownloaderTask();}}返回null;}//我们的缓存功能//查找目录以保存缓存的图像私有静态文件getCacheDirectory(上下文上下文){字符串sdState=android.os。Environment.getExternalStorageState();文件缓存目录;if(sdState.equals(android.os.Environment.MEDIA_MOUNTED)){文件sdDir=android.os。Environment.getExternalStorageDirectory();//TODO:在此处更改目录cacheDir=新文件(sdDir,“data/ToDo/images”);}其他cacheDir=上下文.getCacheDir();if(!cacheDir.exists())缓存目录.mkdirs();返回cacheDir;}private void writeFile(位图bmp,文件f){FileOutputStream输出=空;尝试{out=新的FileOutputStream(f);bmp.compression(Bitmap.CompressFormat.PNG,80,输出);}catch(异常e){e.printStackTrace();}最后{尝试{if(out!=空)out.close();}catch(异常ex){}}}//下载异步任务公共类BitmapDownloaderTask扩展了AsyncTask{私有字符串url;私有最终WeakReference<ImageView>imageViewReference;公共位图下载程序任务(ImageView ImageView){imageViewReference=新的WeakReference<ImageView>(ImageView);}@覆盖//实际下载方法,在任务线程中运行受保护的位图doInBackground(字符串…参数){//params来自execute()调用:params[0]是url。url=(字符串)参数[0];return downloadBitmap(参数[0]);}@覆盖//下载图像后,将其与imageView关联protected void onPostExecute(位图位图){if(isCancelled()){位图=空;}if(imageViewReference!=空){ImageView ImageView=imageViewReference.get();BitmapDownloaderTask bitmapDonloaderTask=获取位图下载程序任务(图像视图);//仅当此进程仍与关联时才更改位图//它if(this==bitmapDownloaderTask){imageView.setImageBitmap(位图);//缓存图像String filename=String.valueOf(url.hashCode());文件f=新文件(getCacheDirectory(imageView.getContext()),文件名);imageCache.put(f.getPath(),位图);writeFile(位图,f);}}}}静态类DownloadedDrawable扩展了ColorDrawable{私有最终弱引用<BitmapDownloaderTask>bitmapDonloaderTaskReference;public DownloadedDrawable(位图下载程序任务BitmapDownloaderTask){super(彩色,白色);bitmapDownloaderTaskReference=新的WeakReference(位图下载程序任务);}公共BitmapDownloaderTask获取BitmapDownloaderTask(){return bitmapDownloaderTaskReference.get();}}//实际下载代码静态位图下载位图(字符串url){HttpParams params=新的BasicHttpParams();params.setParameter(核心协议PNames.PROTOCOL_VERSION,HttpVersion。HTTP_1_1);HttpClient客户端=新的DefaultHttp客户端(参数);最终HttpGet getRequest=新HttpGet(url);尝试{HttpResponse响应=client.execute(getRequest);final int statusCode=响应.getStatusLine().getStatus代码();if(statusCode!=HttpStatus.SC_OK){Log.w(“ImageDownloader”,“Error”+statusCode+“从”+url“检索位图时);返回null;}最终HttpEntity实体=response.getEntity();if(实体!=空){InputStream InputStream=null;尝试{inputStream=实体.getContent();最终位图位图=位图工厂.decodeStream(inputStream);返回位图;}最后{if(inputStream!=null){inputStream.close();}entity.consumeContent();}}}catch(异常e){//可以为IOException或//非法状态例外getRequest.abort();Log.w(“ImageDownloader”,“从中检索位图时出错”+url+e.toString());}最后{if(客户端!=空){//client.close();}}返回null;}}
0
5

我遇到了这个问题,并实现了lruCache。我认为您需要API 12及更高版本或使用兼容v4库。lurCache是快速内存,但它也有预算,所以如果你担心你可以使用磁盘缓存。。。这一切都在缓存位图.

现在我将提供我的实现,它是一个单子我从这样的地方打电话:

//其中,第一个是字符串,另一个是要加载的图像视图。下载ImageTask.getInstance().loadBitmap(avatarURL,iv_avatar);

以下是在检索web图像时缓存并在适配器的getView中调用上述内容的理想代码:

公共类DownloadImageTask{私有LruCache<String,Bitmap>mMemoryCache;/*创建一个单例类以从多个类调用它*/私有静态DownloadImageTask实例=null;公共静态DownloadImageTask getInstance(){if(实例==空){instance=新的DownloadImageTask();}返回实例;}//从公共实例中锁定构造函数私人下载ImageTask(){//获取最大可用VM内存,超过此数量将引发//OutOfMemory异常。以KB为单位存储,因为LruCache需要//int在其构造函数中。final int maxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);//为此内存缓存使用1/8的可用内存。final int cacheSize=maxMemory/8;mMemoryCache=新LruCache<字符串,位图>(cacheSize){@覆盖protected int sizeOf(字符串键,位图位图){//缓存大小将以KB而不是//项目数量。return bitmap.getByteCount()/1024;}};}public void loadBitmap(String avatarURL,ImageView ImageView){final String imageKey=String.valueOf(化身URL);最终位图=getBitmapFromMemCache(imageKey);if(位图!=空){imageView.setImageBitmap(位图);}其他{imageView.setImageResource(R.drawable.ic_launcher);new DownloadImageTaskViaWeb(imageView).execute(avatarURL);}}private void addBitmapToMemoryCache(字符串键,位图){if(getBitmapFromMemCache(key)==空){mMemoryCache.put(键,位图);}}private位图getBitmapFromMemCache(字符串键){return mMemoryCache.get(key);}/*打开http流并解码web图像的后台进程*/类DownloadImageTaskViaWeb扩展了AsyncTask{ImageView bmImage;公共下载ImageTaskViaWeb(ImageView bmImage){this.bmImage=bmImage;}受保护的位图doInBackground(字符串…urls){字符串urldisplay=urls[0];位图mIcon=空;尝试{InputStream in=new java.net。URL(urldisplay).openStream();mIcon=BitmapFactory.decodeStream(in);} catch(异常e){Log.e(“错误”,e.getMessage());e.printStackTrace();}addBitmapToMemoryCache(String.valueOf(urldisplay),mIcon);返回mIcon;}/*解码后,我们更新主UI上的视图*/protected void onPostExecute(位图结果){bmImage.setImageBitmap(结果);}}}

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.