Android – Asynchronous image loading in ListView

Problem: How to load images in ListView asynchronously, and also caching the images?

I am writing this article based on the many requests/feedbacks and i saw many developers on Stackoverflow facing the problem of loading images in ListView asynchronously. This is not an easy task, yes it will be but after reading and implementing the code given in this tutorial 

If you are newbie in Android development then i would suggest you to refer the articles/tutorials given in ListView category.

And I am sure you have gone through my previous article: Android – Load images from web and caching. where i have talked about loading single images from web and caching the same. Now here today, i will talk about to load images in listview. Just think what if we dont implement asynchronous loading of images? It will suck and user will go away from your application, so do you want the same? If no then i would suggest you to implement Lazy Loading (Load images asynchronously).

If you have gone through my previous article then it would be easy to go through this article. Because in this article we just has to implement ListView and create adapter to load images and data.

Step 1: create XML layout for ListView.
activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><ListViewandroid:id="@+id/listView1"android:layout_width="match_parent"android:layout_height="wrap_content"android:cacheColorHint="@android:color/transparent"android:divider="@android:color/transparent"android:dividerHeight="10dp"android:fadingEdge="none"android:listSelector="@android:color/transparent"android:padding="10dp" ></ListView></LinearLayout>

Step 2: Create Row file for ListView items
row_listview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:background="@drawable/btn_white_matte" ><ImageViewandroid:id="@+id/image"android:layout_width="50dip"android:layout_height="50dip"android:scaleType="centerCrop"android:src="@drawable/ic_launcher" /><TextViewandroid:id="@+id/text"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="left|center_vertical"android:layout_marginLeft="10dip"android:layout_weight="1"android:textSize="20dip" /></LinearLayout>

Step 3: Create adapter for ListView
LazyAdapter.java

package com.technotalkative.loadwebimage;import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;import com.technotalkative.loadwebimage.imageutils.ImageLoader;public class LazyAdapter extends BaseAdapter {private Activity activity;private String[] data;private static LayoutInflater inflater=null;public ImageLoader imageLoader; public LazyAdapter(Activity a, String[] d) {activity = a;data=d;inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);imageLoader=new ImageLoader(activity.getApplicationContext());}public int getCount() {return data.length;}public Object getItem(int position) {return position;}public long getItemId(int position) {return position;}public View getView(int position, View convertView, ViewGroup parent) {View vi=convertView;if(convertView==null)vi = inflater.inflate(R.layout.row_listview_item, null);TextView text=(TextView)vi.findViewById(R.id.text);;ImageView image=(ImageView)vi.findViewById(R.id.image);text.setText("item "+position);imageLoader.DisplayImage(data[position], image);return vi;}
}

Step 4: Create MainActivity.java file 
MainActivity.java

package com.technotalkative.loadwebimage;import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;public class MainActivity extends Activity {ListView list;LazyAdapter adapter;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);list=(ListView)findViewById(R.id.listView1);adapter=new LazyAdapter(this, imageUrls);list.setAdapter(adapter);}@Overridepublic void onDestroy(){list.setAdapter(null);super.onDestroy();}private String imageUrls[] = {"https://si0.twimg.com/profile_images/2053165008/ac-new_bigger.jpg","https://si0.twimg.com/profile_images/1751120073/green-android-rotate-02__1__copy_9_bigger.jpeg","https://si0.twimg.com/profile_images/2508170683/m8jf0po4imu8t5eemjdd_bigger.png","https://si0.twimg.com/profile_images/1517737798/aam-twitter-right-final_bigger.png","https://si0.twimg.com/profile_images/1265264136/twitter_bg3_bigger.png","https://si0.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_bigger.png","https://si0.twimg.com/profile_images/839219643/gals_twitter_bigger.png","https://si0.twimg.com/profile_images/2244328948/ADC4_Twitter_128_bigger.jpg","https://si0.twimg.com/profile_images/956404323/androinica-avatar_bigger.png","https://si0.twimg.com/profile_images/1417650153/android-hug_bigger.png","https://si0.twimg.com/profile_images/1084169260/twitter_logo3_bigger.png","https://si0.twimg.com/profile_images/895713856/android_large_bigger.png","https://si0.twimg.com/profile_images/328066023/droid_con150_bigger.jpg","https://si0.twimg.com/profile_images/909231146/Android_Biz_Man_bigger.png","https://si0.twimg.com/profile_images/77641093/AndroidPlanet_bigger.png","https://si0.twimg.com/profile_images/60788468/androffice_bigger.png","https://si0.twimg.com/profile_images/262620111/logodroid_bigger.png","https://si0.twimg.com/profile_images/1024243227/Android-Apps_bigger.jpg","https://si0.twimg.com/profile_images/2172264088/logo-testa-quad_bigger.png","https://si0.twimg.com/profile_images/1186449790/mestre-android-twitter_bigger.jpg","https://si0.twimg.com/profile_images/1785885571/androidvenezuela_bigger.png"};
}

Step 5: Import Required classes

These are the required classes for loading image asynchronously and caching into the local memory storage.
1) ImageLoader
2) MemoryCache
3) FileCache
4) Utils

ImageLoader.java
Using DisplayImage(Url, ImageView) method of ImageLoader class, you can load and cache image. You just need to provide the web url of image and the imageview in which you want to display loaded image.

package com.technotalkative.loadwebimage.imageutils;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;import com.technotalkative.loadwebimage.R;public class ImageLoader {MemoryCache memoryCache=new MemoryCache();FileCache fileCache;private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());ExecutorService executorService; public ImageLoader(Context context){fileCache=new FileCache(context);executorService=Executors.newFixedThreadPool(5);}final int stub_id=R.drawable.ic_launcher;public void DisplayImage(String url, ImageView imageView){imageViews.put(imageView, url);Bitmap bitmap=memoryCache.get(url);if(bitmap!=null)imageView.setImageBitmap(bitmap);else{queuePhoto(url, imageView);imageView.setImageResource(stub_id);}}private void queuePhoto(String url, ImageView imageView){PhotoToLoad p=new PhotoToLoad(url, imageView);executorService.submit(new PhotosLoader(p));}private Bitmap getBitmap(String url) {File f=fileCache.getFile(url);//from SD cacheBitmap b = decodeFile(f);if(b!=null)return b;//from webtry {Bitmap bitmap=null;URL imageUrl = new URL(url);HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();conn.setConnectTimeout(30000);conn.setReadTimeout(30000);conn.setInstanceFollowRedirects(true);InputStream is=conn.getInputStream();OutputStream os = new FileOutputStream(f);Utils.CopyStream(is, os);os.close();bitmap = decodeFile(f);return bitmap;} catch (Throwable ex){ex.printStackTrace();if(ex instanceof OutOfMemoryError)memoryCache.clear();return null;}}//decodes image and scales it to reduce memory consumptionprivate Bitmap decodeFile(File f){try {//decode image sizeBitmapFactory.Options o = new BitmapFactory.Options();o.inJustDecodeBounds = true;BitmapFactory.decodeStream(new FileInputStream(f),null,o);//Find the correct scale value. It should be the power of 2.final int REQUIRED_SIZE=70;int width_tmp=o.outWidth, height_tmp=o.outHeight;int scale=1;while(true){if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)break;width_tmp/=2;height_tmp/=2;scale*=2;}//decode with inSampleSizeBitmapFactory.Options o2 = new BitmapFactory.Options();o2.inSampleSize=scale;return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);} catch (FileNotFoundException e) {}return null;}//Task for the queueprivate class PhotoToLoad{public String url;public ImageView imageView;public PhotoToLoad(String u, ImageView i){url=u; imageView=i;}}class PhotosLoader implements Runnable {PhotoToLoad photoToLoad;PhotosLoader(PhotoToLoad photoToLoad){this.photoToLoad=photoToLoad;}@Overridepublic void run() {if(imageViewReused(photoToLoad))return;Bitmap bmp=getBitmap(photoToLoad.url);memoryCache.put(photoToLoad.url, bmp);if(imageViewReused(photoToLoad))return;BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);Activity a=(Activity)photoToLoad.imageView.getContext();a.runOnUiThread(bd);}}boolean imageViewReused(PhotoToLoad photoToLoad){String tag=imageViews.get(photoToLoad.imageView);if(tag==null || !tag.equals(photoToLoad.url))return true;return false;}//Used to display bitmap in the UI threadclass BitmapDisplayer implements Runnable{Bitmap bitmap;PhotoToLoad photoToLoad;public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}public void run(){if(imageViewReused(photoToLoad))return;if(bitmap!=null)photoToLoad.imageView.setImageBitmap(bitmap);elsephotoToLoad.imageView.setImageResource(stub_id);}}public void clearCache() {memoryCache.clear();fileCache.clear();}}

MemoryCache.java

package com.technotalkative.loadwebimage.imageutils;import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Bitmap;
import android.util.Log;public class MemoryCache {private static final String TAG = "MemoryCache";private Map<String, Bitmap> cache=Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU orderingprivate long size=0;//current allocated sizeprivate long limit=1000000;//max memory in bytespublic MemoryCache(){//use 25% of available heap sizesetLimit(Runtime.getRuntime().maxMemory()/4);}public void setLimit(long new_limit){limit=new_limit;Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");}public Bitmap get(String id){try{if(!cache.containsKey(id))return null;//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 return cache.get(id);}catch(NullPointerException ex){ex.printStackTrace();return null;}}public void put(String id, Bitmap bitmap){try{if(cache.containsKey(id))size-=getSizeInBytes(cache.get(id));cache.put(id, bitmap);size+=getSizeInBytes(bitmap);checkSize();}catch(Throwable th){th.printStackTrace();}}private void checkSize() {Log.i(TAG, "cache size="+size+" length="+cache.size());if(size>limit){Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated  while(iter.hasNext()){Entry<String, Bitmap> entry=iter.next();size-=getSizeInBytes(entry.getValue());iter.remove();if(size<=limit)break;}Log.i(TAG, "Clean cache. New size "+cache.size());}}public void clear() {try{//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 cache.clear();size=0;}catch(NullPointerException ex){ex.printStackTrace();}}long getSizeInBytes(Bitmap bitmap) {if(bitmap==null)return 0;return bitmap.getRowBytes() * bitmap.getHeight();}
}

FileCache.java
Using FileCache, we will create TTImages_cache folder for caching images into it. Also to load image if synced already. We can use clear() method of FileCache class to clear synced images.

package com.technotalkative.loadwebimage.imageutils;import java.io.File;
import android.content.Context;public class FileCache {private File cacheDir;public FileCache(Context context){//Find the dir to save cached imagesif (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"TTImages_cache");elsecacheDir=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());//Another possible solution (thanks to grantland)//String filename = URLEncoder.encode(url);File f = new File(cacheDir, filename);return f;}public void clear(){File[] files=cacheDir.listFiles();if(files==null)return;for(File f:files)f.delete();}}

Utils.java

package com.technotalkative.loadwebimage.imageutils;import java.io.InputStream;
import java.io.OutputStream;public class Utils {public static void CopyStream(InputStream is, OutputStream os){final int buffer_size=1024;try{byte[] bytes=new byte[buffer_size];for(;;){int count=is.read(bytes, 0, buffer_size);if(count==-1)break;os.write(bytes, 0, count);}}catch(Exception ex){}}
}

Note:
Don’t forget to include INTERNET and WRITE_EXTERNAL_STORAGE permission in AndroidManifest.xml

  <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Output:

Download this example from here: https://github.com/PareshMayani/Android-Asynchronous-Image-Loading-Example

All the kudos goes to Fedor Vlasov for providing library for Lazy Loading Images.

About Paresh Mayani

I'm Paresh Mayani, a passionate mobile application developer from India. Having been involved in android app development since 2010. By passion, I am Head/Organizer of Google Developers Group (GDG), Ahmedabad

android图片异步加载解决步骤相关推荐

  1. Android 图片异步加载的体会,SoftReference已经不再适用

    在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的方式 ...

  2. Android 图片异步加载

    所谓图片异步加载,意思是不用一次把图片全部加载完,你可以叫它延迟加载,缓冲加载都行. 看看你有没有这种需求:某篇文章图片很多,如果在载入文章时就载入所有图片,无疑会延缓载入速度,让用户等更久,所以,我 ...

  3. android图片异步加载图片,Android 异步加载图片分析总结

    研究了android从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new ...

  4. android webview 图片异步加载,Webview 图片异步加载及bug解决

    在项目中新闻显示需要使用图片的异步加载,并且在加载图片前和加载图片失败时显示默认图片. 关于webview中图片的异步加载的思路如下: 方案一:由前端同学全权负责(使用js实现异步加载) 方案二:an ...

  5. android复位机器人图片_Universal-Image-Loader 图片异步加载类库还不熟?

    码个蛋(codeegg) 第 824 次推文 作者:欢醉 博客:https://cloud.tencent.com/developer/article/1026386 码妞看世界 写在前面 这个图片异 ...

  6. android listview 异步加载图片并防止错位

    网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertVie ...

  7. android 实现异步加载图片,Android中ImageView异步加载图片类

    本源码是从网络找到经修改以方便直接调用感觉用着还可以 首先在项目中添加一个专门加载图片的类AsyncImageLoaderpackage com.demo.core; import java.io.I ...

  8. 又优化了一下 Android ListView 异步加载图片

    写这篇文章并不是教大家怎么样用listview异步加载图片,因为这样的文章在网上已经有很多了,比如这位仁兄写的就很好: http://www.iteye.com/topic/685986 我也是因为看 ...

  9. Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

    UIL( Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)) http://blog.csdn.net/vipzjyno1/article/detai ...

最新文章

  1. win8 远程桌面时提示凭证不工作问题的终极解决办法
  2. Android 网络请求详解
  3. django批量form表单处理
  4. python适用场景_你真的了解Python吗?什么场景使用多线程,什么场景使用多进程?...
  5. 修补分支提交注意事项
  6. linux 固定usb设备,linux下多个usb设备固定名称方法
  7. boost::stl_interfaces模块实现反向迭代器的测试程序
  8. Android_Kotlin 代码学习
  9. 【Eclipse 插件】Subclipse
  10. 【转】VS2010新建Web网站与新建Web应用程序的区别
  11. 程序员提高编程能力万无一失的办法
  12. cygwin-1.7 离线安装包_【软件安装管家】ArcGIS 10.7 软件安装包+安装教程
  13. LeetCode OJ - Longest Substring Without Repeating Characters
  14. hikey970学习-003:DDK用户手册学习《Huawei HiAI DDK User Manual 》(1)
  15. 11 Component Composition
  16. Python绘制正态分布图及求分位数
  17. wordpress提示“Error establishing a database connection“的解决办法
  18. android 时间管理app,六个时间管理App推荐,让你效率大增
  19. 啥水平?谷歌程序员:我用东北方言编程
  20. 【Flutter从入门到实战】⑪、豆瓣案例-1、星星评分Widget、虚线Widget、TabbarWidget、BottomNavigationBarItem的封装、初始化配置抽取

热门文章

  1. 【转】去掉换行符的几个方法
  2. ecshop设置一个子类对应多个父类并指定跳转url的修改方法
  3. cornerstone 库删除 后 重新添加 ,引用找不到,
  4. Hadoop---集群安装
  5. linux access
  6. JavaScript玩转机器学习:张量(Tensors) 和 操作(operations)
  7. Spring MVC异常处理 - @ ControllerAdvice,@ ExceptionHandler,HandlerExceptionResolver
  8. 地图中添加沿线文字标注
  9. 大数据 Hive spark Flink 关系
  10. C#LeetCode刷题之#645-错误的集合(Set Mismatch)