2083

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

图像总数不固定。

6
  • 13
    你可以使用GreenDroid的异步图像视图.只需打电话设置URL. 评论 2011年12月9日15:11
  • 8
    我已经用过了。这是一个很好的实现。坏消息是,AsyncImageView是一个大型GreenDroid项目的一部分,这使得您的应用程序更大,即使在这种情况下,您所需要的只是AsyncImageView。此外,GreenDroid项目似乎自2011年以来就没有更新过。 评论 2012年4月15日11:06
  • 6
    您甚至可以尝试使用此库:Android-http-image-manager机器人在我看来,它最适合异步加载图像。 评论 2012年11月9日11:43
  • 36
    只要用毕加索的作品,一切都会自己完成的。”毕加索.with(yourContext).load(img src/path/drawable here).into(imageView即您的目标);'就是这样! 评论 2014年1月23日6:40
  • 10
    尝试使用:github.com/nostra13/Android-Universal-Image-Loader,此库对于延迟加载和图像缓存非常快速高效
    – 髌骨肌
    评论 2014年8月16日5:44

41个答案41

重置为默认值
5

你可以试试采水场安卓用于延迟加载图像和列表视图的库。。。以下代码可能会对您有所帮助。。。。。从这里下载库.

AQuery aq=新的AQuery(mContext);aq.id(R.id.image1).image(“http://data.whicdn.com/images/63995806/original.jpg");
4

我使用droidQuery。有两种机制可以从URL加载图像。第一种(速记)很简单:

$.with(myView).image(url);

这可以添加到定制获取视图(…)方法非常简单。


长手法将提供更多的控制,这里甚至没有讨论选项(例如缓存和回调),但是可以在这里找到一个基本实现,它将输出大小指定为200px x 200px:

$.ajax(新AjaxOptions().url(url).type(“GET”).dataType(“图像”).imageWidth(200).imageHeight(200).success(新函数()){@覆盖公共void调用($droidQuery,Object…params){myImageView.setImageBitmap((位图)参数[0]);}}).error(新函数(){@覆盖公共void调用($droidQuery,Object…params){AjaxError e=(AjaxEror)参数[0];Log.e(“$”,“Error”+e.status+“:”+e.Error);}}));
4

使用below类在listview中下载和加载图像。下载后,它会缓存每个图像。还加载图像和延迟加载。

包com.fudiyoxpress.images;导入java.io.File;导入java.io.FileInputStream;导入java.io.FileNotFoundException;导入java.io.FileOutputStream;导入java.io.IOException;导入java.io.InputStream;导入java.io.OutputStream;导入java.net。HttpURL连接;导入java.net。URL;导入java.util。收藏;导入java.util。地图;导入java.util。WeakHashMap;导入java.util.concurrent。执行服务;导入java.util.concurrent。执行人;导入android.content。语境;导入android.graphics。位图;导入android.graphics。位图工厂;导入android.os。经办人;导入android.widget。ImageView;导入com.fudiyoxpress。R;导入com.fudiyoxpress.config。配置;进口com.fudiyoxpress.twitter。缩放位图;公共类ImageLoader{//初始化MemoryCache内存缓存内存缓存=新内存缓存();FileCache FileCache;上下文C;//创建Map(集合)以在键值对中存储图像和图像url私有Map<ImageView,String>imageViews=集合.synchronizedMap(新的WeakHashMap<ImageView,String>());ExecutorService ExecutorService;//在UI线程中显示图像的处理程序处理程序处理程序=new Handler();公共ImageLoader(上下文上下文){C=上下文;fileCache=新的fileCache(上下文);//创建重用固定数量的线程池//在共享的无限队列中运行的线程。executorsService=Executors.newFixedThreadPool(5);}//列表中显示的默认图像(在线图像下载之前)final int stub_id=R.drawable.restlogo占位符;public void DisplayImage(String url,ImageView ImageView,Context Context,布尔header_flag){Bitmap largeIcon=BitmapFactory.decodeResource(context.getResources(),R.drawable.restlogo占位符);header_flag=假;//在地图中存储图像和urlimageViews.put(imageView,url);//检查图像是否存储在MemoryCache Map中(请参阅//MemoryCache.java)位图Bitmap=memoryCache.get(url);if(位图!=null){//如果图像存储在MemoryCache Map中,则//在列表视图行中显示图像位图b=缩放位图.getScaledBitmap(上下文、位图、标头标记);imageView.setImageBitmap(b);}其他{//将要从url下载的照片排队queuePhoto(url、imageView、header_flag);//下载图像前显示默认图像imageView.setImageBitmap(ScaleBitmap.getScaledBitmap)(上下文,largeIcon,header_flag));}}private void queuePhoto(字符串url,ImageView ImageView,boolean header_flag){//在PhotoToLoad对象中存储图像和urlPhotoToLoad p=新的PhotoToLoad(url、imageView、header_flag);//将PhotoToLoad对象传递给PhotosLoader可运行类//并将PhotosLoader runnable提交给执行程序以运行runnable//提交PhotosLoader可运行任务以执行executorService.submit(新PhotosLoader(p));}//队列的任务私有类PhotoToLoad{公共字符串url;公共ImageView ImageView;公共布尔b;公共PhotoToLoad(String u,ImageView i,boolean header_flag){url=u;imageView=i;b=标头标记;}}类PhotosLoader实现Runnable{光电负载光电负载;PhotosLoader(PhotoToLoad PhotoToLoad){this.photoToLoad=照片加载;}@覆盖公共void run(){尝试{//检查图像是否已下载if(图像视图重用(photoToLoad))回报;//从web url下载图像位图bmp=getBitmap(photoToLoad.url);//在内存缓存中设置图像数据memoryCache.put(photoToLoad.url,bmp);if(图像视图重用(photoToLoad))回报;//获取要显示的位图BitmapDisplayer bd=新的位图显示程序(bmp,photoToLoad);//使Runnable bd(BitmapDisplayer)添加到//消息队列。//runnable将在该处理程序的线程上运行//已附加。//BitmapDisplayer运行方法将调用handler.post(bd);}catch(投掷th){//th.printStackTrace();}}}private Bitmap getBitmap(字符串url){文件f=fileCache.getFile(url);//从SD缓存//检查:如果尝试解码缓存中不存在的文件,则返回null位图b=解码文件(f);如果(b!=空)返回b;//从web下载图像文件尝试{////下载图像位图位图=空;URL imageURL=空;尝试{imageURL=新URL(Config.WEB_URL+“/ServeBlob?id=”+URL);HttpURLConnection连接=(HttpURL连接)图像URL.openConnection();connection.setDoInput(true);connection.connect();//if(!(新文件(imageURL.toString())).exists())// {//imageURL=新URL(“”);// }InputStream InputStream=连接.getInputStream();//构造一个新的FileOutputStream,写入//文件//如果文件不存在,则将创建文件OutputStream os=新文件输出流(f);//参见Utils类CopyStream方法//它将从输入流和//将像素写入输出流(文件)实用程序。CopyStream(输入流,操作系统);os.close();位图工厂。选项选项=新BitmapFactory。选项();options.inSampleSize=8;bitmap=BitmapFactory.decodeStream(inputStream,null,options);}捕获(IOException e){//e.printStackTrace();}//现在文件已创建,并将按定义的高度调整文件大小//解码图像并缩放图像以减少内存消耗bitmap=解码文件(f);返回位图;}抓钩(可抛前){例如,printStackTrace();if(OutOfMemoryError实例除外)memoryCache.clear();返回null;}}//解码图像并缩放图像以减少内存消耗私有位图解码文件(文件f){尝试{//解码图像大小位图工厂。选项o=新BitmapFactory。选项();o.inJustDecodeBounds=真;FileInputStream流1=新的FileInput流(f);BitmapFactory.decodeStream(stream1,null,o);流1.关闭();//找到正确的比例值。它应该是2的力量。//设置重新创建图像的宽度/高度最终int REQUIRED_SIZE=85;int width_tmp=o.outWidth,height_tmp=o.outHeight;整数刻度=1;while(真){如果(width_tmp/2<REQUIRED_SIZE||height_tmp/2<所需尺寸)断裂;宽度tmp/=2;高度tmp/=2;刻度*=2;}//用当前刻度值解码位图工厂。选项o2=新的BitmapFactory。选项();o2.inSampleSize=刻度;FileInputStream流2=新的FileInput流(f);位图位图=BitmapFactory.decodeStream(stream2,null,o2);stream2.close();返回位图;}catch(FileNotFoundException e){}捕获(IOException e){e.printStackTrace();}返回null;}布尔图像视图重用(PhotoToLoad PhotoToLoad){字符串标记=imageViews.get(photoToLoad.imageView);//检查url已存在于imageViews MAP中if(tag==null||!tag.equals(photoToLoad.url))返回true;返回false;}//用于在UI线程中显示位图BitmapDisplayer类实现Runnable{位图位图;光电负载光电负载;公共位图显示器(位图b,PhotoToLoad p){位图=b;photoToLoad=p;}公共void run(){if(图像视图重用(photoToLoad))回报;//在UI上显示位图if(位图!=空){photoToLoad.imageView.setImageBitmap(缩放位图.getScaledBitmap(C,位图,photoToLoad/b);}其他{}//photoToLoad.imageView.setImageResource(stub_id);}}public void clearCache(){//清除缓存目录下载的图像和地图中存储的数据memoryCache.clear();fileCache.clear();}}包com.fudiyoxpress.images;导入java.util。收藏;导入java.util。迭代器;导入java.util。LinkedHashMap;导入java.util。地图;导入java.util。地图。进入;导入android.graphics。位图;导入android.util。日志;公共类MemoryCache{private static final String TAG=“MemoryCache”;//LRU订购的最后一个参数为true私有映射<String,Bitmap>cache=Collections.synchronizedMap(new LinkedHashMap<字符串,位图>(10,1.5f,true));//当前分配的大小私有长大小=0;//用于下载图像的最大内存缓存文件夹(以字节为单位)私人长期限额=1000000;公共内存缓存(){//使用可用堆大小的25%setLimit(Runtime.getRuntime().maxMemory()/4);}公共void setLimit(long new_limit){limit=new_limit;Log.i(标签,“MemoryCache将使用最多”+limit/1024./1024.+“MB”);}public Bitmap get(字符串id){尝试{if(!cache.containsKey(id))返回null;//此处有时会发生NullPointerExceptionhttp://code.google.com/p/osmdroid/issues/detail?id=78 return-cache.get(id);}catch(NullPointerException ex){例如,printStackTrace();返回null;}}public void put(字符串id,位图){尝试{if(cache.containsKey(id))大小-=getSizeInBytes(cache.get(id));cache.put(id,位图);size+=getSizeInBytes(位图);checkSize();}catch(投掷th){th.printStackTrace();}}私有void checkSize(){Log.i(TAG,“缓存大小=”+大小+“长度=”+缓存大小());if(大小>限制){迭代器iter=cache.entrySet().Iterator()//最近访问次数最少的项目将是第一个迭代的项目while(iter.hasNext()){Entry<String,Bitmap>Entry=iter.next();size-=getSizeInBytes(entry.getValue());iter.remove();if(大小<=限制)断裂;}Log.i(TAG,“Clean cache.New size”+cache.size());}}公共void clear(){尝试{//此处有时会出现NullPointerExceptionhttp://code.google.com/p/osmdroid/issues/detail?id=78 cache.clear();大小=0;}catch(NullPointerException ex){例如,printStackTrace();}}long getSizeInBytes(位图位图){if(位图==空)返回0;return bitmat.getRowBytes()*位图.getHeight();}}包com.fudiyoxpress.images;导入java.io.InputStream;导入java.io.OutputStream;公共类实用程序{公共静态void CopyStream(InputStream是,OutputStream-os){最终int buffer_size=1024;尝试{byte[]字节=新字节[buffer_size];用于(;;){//从输入流读取字节int计数=为.read(字节,0,缓冲区大小);如果(计数==-1)断裂;//从输出流写入字节os.write(字节,0,计数);}}catch(异常ex){}}}
4

我找到了滑翔机作为比毕加索.我在用毕加索装货32周围大小的图像200-500KB每个人和我总是得到OOM公司.但是滑翔机解决了我的所有问题OOM公司问题。

1
  • 当然,毕加索会为缓存存储完整的图像大小,而Glide只存储优化后的图像。
    – 安特人
    评论 2018年1月8日9:26

一些答案已经提到使用各种图像库,如Universal image Loader和androidimageloader等。这是一个古老的问题,但对于仍在寻找类似内容的人来说,有几个这样的库用于图像加载/缓存。

另一种方法是通过getView()方法中线程中的适配器:

Thread pics_Thread=新线程(new Runnable(){@覆盖公共void run(){位图位图=getPicture(url);if(位图!=空){runOnUiThread(新的Runnable(){@覆盖公共void run(){holder.imageview.setImageBitmap(位图);适配器.notifyDataSetChanged();}                       });             }       }                       });pics_thread.start();

当然,您应该始终缓存图像以避免额外的操作,您可以将图像放在HashMap数组中,检查图像是否存在于数组中,如果不存在,则继续执行线程,或者从HashMap数组加载图像。还要经常检查内存是否泄漏,位图和可绘制文件通常占用大量内存。由您来优化代码。

1
  • 当然,我喜欢在不同的线程中获取位图。但是,在getView()中使用此代码的唯一问题是,将有许多线程为多个映像运行。getView可能会尝试一次加载多个或多个图像。 评论 2015年6月7日8:31

您可以使用一些第三方库,例如毕卡索排球以实现有效的延迟加载。您还可以通过实现以下内容创建自己的

  1. 实现从url下载图像的代码

  2. 实现用于存储和检索图像的缓存机制(使用LruCache公司用于缓存的android)

2

更新:如果你想在2020年找到一个由Kotlin Coroutines支持的解决方案,试试Coil。

Coil是Coroutine图像加载器.

特征

  1. 快速:Coil执行了许多优化,包括内存和磁盘缓存、对内存中的图像进行降采样、重新使用位图、自动暂停/取消请求等。
  2. 轻量级:Coil为您的APK添加了约2000个方法(对于已经使用OkHttp和Coroutines的应用程序),这与毕加索且显著低于滑翔机壁画.
  3. 易于使用:Coil的API利用了Kotlin的语言特性,实现了简单性和最少的样板文件。
  4. 现代:Coil是Kotlin-first,使用现代库,包括Coroutines、OkHttp、Okio和AndroidX生命周期。

放坡设置:

线圈可用于mavenCentral().

实现(“io.coil-kt:coil:1.0.0”)

快速入门

要将图像加载到ImageView中,请使用加载扩展函数:

//URL地址imageView.load(“https://www.example.com/image.jpg")//资源imageView.load(R.drawable.image)//文件imageView.load(文件(“/path/to/image.jpg”))

或在后台线程上

//线圈(暂停当前协同程序;非阻塞和线程安全)val请求=图像请求。生成器(上下文).data(url).尺寸(宽度、高度).build()val drawable=context.imageLoader.execute(request).drawable

你也可以迁移来自毕加索/格莱德

完整文档在这里

1

除了异步加载数据缓存外,您可能需要UI缓存,如设置视图缓存大小

除了加载可见项数据外,您可能需要加载近似可见项数据

AndroidX分页库是另一个选项,例如,您可以从SQLite数据库加载、缓存10000000个项目并将其显示到RecyclerView。参考页面列表

例子:假设列表视图可见项目为[6,7,8,9,10],您可能需要加载[6,7,8,9,10]并预加载项目[1,2,3,4,5]和[11,12,13,14,15],因为用户可能会滚动到前页或后页

1
  • 除了您的描述之外,请包括一些代码以进一步改进您的答案。
    – 布泽克
    评论 2016年6月14日16:09
1

滑翔机

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

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

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

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

Glide图书馆

毕加索

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

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

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

毕加索.with(context).load(“your-url-here”).into(imageView);

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

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

毕加索图书馆

0

这就是你要做的Jetpack组合.

实现(“io.coil-kt:coil-compose:1.3.1”)//添加coil-compose库
图像(painter=rememberImagePainter(“https://www.example.com/image.jpg"),contentDescription=“我的图像描述”,modifier=修改器大小(128.dp))

感谢nglauber和Gabriele Mariotti回答。

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