In this example downloading images from web to a listview. Using lazy loading to download images in a listview. Using custom adapter to create lisview rows and using ImageLoader class to lazy load images from web and show in listview row. Click on listview showing image url in alert.
Steps :
MainActivity.java : Initialize static image url in string array and create listview.
LazyImageLoadAdapter.java : Used to create each list row. Inflate tabitem.xml file for each row and call ImageLoader.java to download image from url and resize downloaded image cache on sdcard.
ImageLoader.java : Used to download image from url and resize downloaded image and make file cache on sdcard. Lazy load images for listview rows.
FileCache.java : Used to create folder at sdcard and create map to store downloaded image information.
MemoryCache.java : Used to set cache folder size limit ( How much mb/kb downloaded image cache folder will store ) and also used to clear cache files from sdcard.
Utils.java : Used to Create Cache image for images downloaded from web.
LazyImageLoadAdapter.java : Used to create each list row. Inflate tabitem.xml file for each row and call ImageLoader.java to download image from url and resize downloaded image cache on sdcard.
ImageLoader.java : Used to download image from url and resize downloaded image and make file cache on sdcard. Lazy load images for listview rows.
FileCache.java : Used to create folder at sdcard and create map to store downloaded image information.
MemoryCache.java : Used to set cache folder size limit ( How much mb/kb downloaded image cache folder will store ) and also used to clear cache files from sdcard.
Utils.java : Used to Create Cache image for images downloaded from web.
Example Flow :
Project Structure :
File : AndroidManifest.xml
- Define android.permission.WRITE_EXTERNAL_STORAGE and android.permission.INTERNET permissions.
<? xml version = "1.0" encoding = "utf-8" ?> < manifest xmlns:android = "http://schemas.android.com/apk/res/android" package = "com.androidexample.lazyimagedownload" android:versionCode = "1" android:versionName = "1.0" debuggable = "true" > < application android:icon = "@drawable/icon" android:label = "@string/app_name" > < activity android:name = "com.androidexample.lazyimagedownload.MainActivity" android:label = "@string/app_name" android:configChanges = "keyboardHidden|orientation" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > </ application > < uses-sdk android:minSdkVersion = "8" /> < uses-permission android:name = "android.permission.INTERNET" /> < uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" /> </ manifest > |
File : main.xml
- This file used to show main activity screen.
- Define ListView in this file.
- Define ListView in this file.
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < ListView android:id = "@+id/list" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:layout_weight = "1" /> < Button android:id = "@+id/button1" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "Refresh cache" /> </ LinearLayout > |
File : MainActivity.java
- Define number of image urls in a string array.
- Call adapter class to create listview rows.
- Call adapter class to create listview rows.
package com.androidexample.lazyimagedownload; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends Activity { ListView list; LazyImageLoadAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); list=(ListView)findViewById(R.id.list); // Create custom adapter for listview adapter= new LazyImageLoadAdapter( this , mStrings); //Set adapter to listview list.setAdapter(adapter); Button b=(Button)findViewById(R.id.button1); b.setOnClickListener(listener); } @Override public void onDestroy() { // Remove adapter refference from list list.setAdapter( null ); super .onDestroy(); } public OnClickListener listener= new OnClickListener(){ @Override public void onClick(View arg0) { //Refresh cache directory downloaded images adapter.imageLoader.clearCache(); adapter.notifyDataSetChanged(); } }; public void onItemClick( int mPosition) { String tempValues = mStrings[mPosition]; Toast.makeText(MainActivity. this , "Image URL : " +tempValues, Toast.LENGTH_LONG).show(); } // Image urls used in LazyImageLoadAdapter.java file private String[] mStrings={ }; } |
File : LazyImageLoadAdapter.java
- Create custom adapter.
- Inflate tabitem.xml file to create rows in listview.
- Call ImageLoader.java to download and cache images from web.
package com.androidexample.lazyimagedownload;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
//Adapter class extends with BaseAdapter and implements with OnClickListener
public class LazyImageLoadAdapter extends BaseAdapter implements OnClickListener{
private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyImageLoadAdapter(Activity a, String[] d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Create ImageLoader object to download and show image in list
// Call ImageLoader constructor to initialize FileCache
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;
}
/********* Create a holder Class to contain inflated xml file elements *********/
public static class ViewHolder{
public TextView text;
public TextView text1;
public TextView textWide;
public ImageView image;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
ViewHolder holder;
if(convertView==null){
/****** Inflate tabitem.xml file for each row ( Defined below ) *******/
vi = inflater.inflate(R.layout.listview_row, null);
/****** View Holder Object to contain tabitem.xml file elements ******/
holder = new ViewHolder();
holder.text = (TextView) vi.findViewById(R.id.text);
holder.text1=(TextView)vi.findViewById(R.id.text1);
holder.image=(ImageView)vi.findViewById(R.id.image);
/************ Set holder with LayoutInflater ************/
vi.setTag( holder );
}
else
holder=(ViewHolder)vi.getTag();
holder.text.setText("Company "+position);
holder.text1.setText("company description "+position);
ImageView image = holder.image;
//DisplayImage function from ImageLoader Class
imageLoader.DisplayImage(data[position], image);
/******** Set Item Click Listner for LayoutInflater for each row ***********/
vi.setOnClickListener(new OnItemClickListener(position));
return vi;
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
/********* Called when Item click in ListView ************/
private class OnItemClickListener implements OnClickListener{
private int mPosition;
OnItemClickListener(int position){
mPosition = position;
}
@Override
public void onClick(View arg0) {
MainActivity sct = (MainActivity)activity;
sct.onItemClick(mPosition);
}
}
}
File : File : listview_row.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/bar_bg_thin"
android:paddingTop="0dip" android:layout_gravity="top"
>
<TableRow >
<LinearLayout
android:layout_width="70dp"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
>
<ImageView
android:layout_gravity="left|top"
android:scaleType="centerCrop"
android:id="@+id/image"
android:src="@drawable/stub"
android:layout_width="50dip"
android:layout_height="50dip"
/>
</LinearLayout>
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="0dip" android:layout_gravity="top"
>
<TableRow>
<TextView
android:id="@+id/text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1" android:layout_gravity="left|center_vertical"
android:textSize="14sp"
android:layout_marginLeft="10dip"
android:layout_marginTop="2dip"
android:textColor="#000000"
android:layout_span="1"
/>
</TableRow>
<TableRow>
<TextView
android:text=""
android:id="@+id/text1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_gravity="left|center_vertical"
android:textSize="11sp"
android:textColor="#000000"
android:layout_marginLeft="10dip"
android:layout_marginTop="4dip"
android:gravity="left"/>
</TableRow>
</TableLayout>
<ImageView
android:layout_height="30dp"
android:layout_width="30dp"
android:scaleType="centerCrop"
android:background="@drawable/dislike1"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:gravity="left"
/>
</TableRow>
</TableLayout>
File : ImageLoader.java
- Used to download images from web and resize.
- Lazy load images in listview.
- Further explanation See in comments.
package com.androidexample.lazyimagedownload;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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.os.Handler;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
public class ImageLoader {
// Initialize MemoryCache
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
//Create Map (collection) to store image and image url in key value pair
private Map<ImageView, String> imageViews = Collections.synchronizedMap(
new WeakHashMap<ImageView, String>());
ExecutorService executorService;
//handler to display images in UI thread
Handler handler = new Handler();
public ImageLoader(Context context){
fileCache = new FileCache(context);
// Creates a thread pool that reuses a fixed number of
// threads operating off a shared unbounded queue.
executorService=Executors.newFixedThreadPool(5);
}
// default image show in list (Before online image download)
final int stub_id=R.drawable.stub;
public void DisplayImage(String url, ImageView imageView)
{
//Store image and url in Map
imageViews.put(imageView, url);
//Check image is stored in MemoryCache Map or not (see MemoryCache.java)
Bitmap bitmap = memoryCache.get(url);
if(bitmap!=null){
// if image is stored in MemoryCache Map then
// Show image in listview row
imageView.setImageBitmap(bitmap);
}
else
{
//queue Photo to download from url
queuePhoto(url, imageView);
//Before downloading image show default image
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
// Store image and url in PhotoToLoad object
PhotoToLoad p = new PhotoToLoad(url, imageView);
// pass PhotoToLoad object to PhotosLoader runnable class
// and submit PhotosLoader runnable to executers to run runnable
// Submits a PhotosLoader runnable task for execution
executorService.submit(new PhotosLoader(p));
}
//Task for the queue
private 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;
}
@Override
public void run() {
try{
//Check if image already downloaded
if(imageViewReused(photoToLoad))
return;
// download image from web url
Bitmap bmp = getBitmap(photoToLoad.url);
// set image data in Memory Cache
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
// Get bitmap to display
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
// Causes the Runnable bd (BitmapDisplayer) to be added to the message queue.
// The runnable will be run on the thread to which this handler is attached.
// BitmapDisplayer run method will call
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
//CHECK : if trying to decode file which not exist in cache return null
Bitmap b = decodeFile(f);
if(b!=null)
return b;
// Download image file from web
try {
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();
// Constructs a new FileOutputStream that writes to file
// if file not exist then it will create file
OutputStream os = new FileOutputStream(f);
// See Utils class CopyStream method
// It will each pixel from input stream and
// write pixels to output stream (file)
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
//Now file created and going to resize file with defined height
// Decodes image and scales it to reduce memory consumption
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 consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
// Set width/height of recreated image
final int REQUIRED_SIZE=85;
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 current scale values
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
//Check url is already exist in imageViews MAP
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
// Show bitmap on UI
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
//Clear cache directory downloaded images and stored data in maps
memoryCache.clear();
fileCache.clear();
}
}
File : FileCache.java
package com.androidexample.lazyimagedownload;
import java.io.File;
import android.content.Context;
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir at SDCARD to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
{
//if SDCARD is mounted (SDCARD is present on device and mounted)
cacheDir = new File(
android.os.Environment.getExternalStorageDirectory(),"LazyList");
}
else
{
// if checking on simulator the create cache dir in your application context
cacheDir=context.getCacheDir();
}
if(!cacheDir.exists()){
// create cache dir in your application context
cacheDir.mkdirs();
}
}
public File getFile(String url){
//Identify images by hashcode or encode by URLEncoder.encode.
String filename=String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
// list all files inside cache directory
File[] files=cacheDir.listFiles();
if(files==null)
return;
//delete all cache directory files
for(File f:files)
f.delete();
}
}
- Create custom adapter.
- Inflate tabitem.xml file to create rows in listview.
- Call ImageLoader.java to download and cache images from web.
package com.androidexample.lazyimagedownload;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
//Adapter class extends with BaseAdapter and implements with OnClickListener
public class LazyImageLoadAdapter extends BaseAdapter implements OnClickListener{
private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyImageLoadAdapter(Activity a, String[] d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Create ImageLoader object to download and show image in list
// Call ImageLoader constructor to initialize FileCache
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;
}
/********* Create a holder Class to contain inflated xml file elements *********/
public static class ViewHolder{
public TextView text;
public TextView text1;
public TextView textWide;
public ImageView image;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
ViewHolder holder;
if(convertView==null){
/****** Inflate tabitem.xml file for each row ( Defined below ) *******/
vi = inflater.inflate(R.layout.listview_row, null);
/****** View Holder Object to contain tabitem.xml file elements ******/
holder = new ViewHolder();
holder.text = (TextView) vi.findViewById(R.id.text);
holder.text1=(TextView)vi.findViewById(R.id.text1);
holder.image=(ImageView)vi.findViewById(R.id.image);
/************ Set holder with LayoutInflater ************/
vi.setTag( holder );
}
else
holder=(ViewHolder)vi.getTag();
holder.text.setText("Company "+position);
holder.text1.setText("company description "+position);
ImageView image = holder.image;
//DisplayImage function from ImageLoader Class
imageLoader.DisplayImage(data[position], image);
/******** Set Item Click Listner for LayoutInflater for each row ***********/
vi.setOnClickListener(new OnItemClickListener(position));
return vi;
}
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
/********* Called when Item click in ListView ************/
private class OnItemClickListener implements OnClickListener{
private int mPosition;
OnItemClickListener(int position){
mPosition = position;
}
@Override
public void onClick(View arg0) {
MainActivity sct = (MainActivity)activity;
sct.onItemClick(mPosition);
}
}
}
File : File : listview_row.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/bar_bg_thin"
android:paddingTop="0dip" android:layout_gravity="top"
>
<TableRow >
<LinearLayout
android:layout_width="70dp"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
>
<ImageView
android:layout_gravity="left|top"
android:scaleType="centerCrop"
android:id="@+id/image"
android:src="@drawable/stub"
android:layout_width="50dip"
android:layout_height="50dip"
/>
</LinearLayout>
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="0dip" android:layout_gravity="top"
>
<TableRow>
<TextView
android:id="@+id/text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1" android:layout_gravity="left|center_vertical"
android:textSize="14sp"
android:layout_marginLeft="10dip"
android:layout_marginTop="2dip"
android:textColor="#000000"
android:layout_span="1"
/>
</TableRow>
<TableRow>
<TextView
android:text=""
android:id="@+id/text1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_gravity="left|center_vertical"
android:textSize="11sp"
android:textColor="#000000"
android:layout_marginLeft="10dip"
android:layout_marginTop="4dip"
android:gravity="left"/>
</TableRow>
</TableLayout>
<ImageView
android:layout_height="30dp"
android:layout_width="30dp"
android:scaleType="centerCrop"
android:background="@drawable/dislike1"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:gravity="left"
/>
</TableRow>
</TableLayout>
File : ImageLoader.java
- Used to download images from web and resize.
- Lazy load images in listview.
- Further explanation See in comments.
package com.androidexample.lazyimagedownload;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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.os.Handler;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
public class ImageLoader {
// Initialize MemoryCache
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
//Create Map (collection) to store image and image url in key value pair
private Map<ImageView, String> imageViews = Collections.synchronizedMap(
new WeakHashMap<ImageView, String>());
ExecutorService executorService;
//handler to display images in UI thread
Handler handler = new Handler();
public ImageLoader(Context context){
fileCache = new FileCache(context);
// Creates a thread pool that reuses a fixed number of
// threads operating off a shared unbounded queue.
executorService=Executors.newFixedThreadPool(5);
}
// default image show in list (Before online image download)
final int stub_id=R.drawable.stub;
public void DisplayImage(String url, ImageView imageView)
{
//Store image and url in Map
imageViews.put(imageView, url);
//Check image is stored in MemoryCache Map or not (see MemoryCache.java)
Bitmap bitmap = memoryCache.get(url);
if(bitmap!=null){
// if image is stored in MemoryCache Map then
// Show image in listview row
imageView.setImageBitmap(bitmap);
}
else
{
//queue Photo to download from url
queuePhoto(url, imageView);
//Before downloading image show default image
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
// Store image and url in PhotoToLoad object
PhotoToLoad p = new PhotoToLoad(url, imageView);
// pass PhotoToLoad object to PhotosLoader runnable class
// and submit PhotosLoader runnable to executers to run runnable
// Submits a PhotosLoader runnable task for execution
executorService.submit(new PhotosLoader(p));
}
//Task for the queue
private 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;
}
@Override
public void run() {
try{
//Check if image already downloaded
if(imageViewReused(photoToLoad))
return;
// download image from web url
Bitmap bmp = getBitmap(photoToLoad.url);
// set image data in Memory Cache
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
// Get bitmap to display
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
// Causes the Runnable bd (BitmapDisplayer) to be added to the message queue.
// The runnable will be run on the thread to which this handler is attached.
// BitmapDisplayer run method will call
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
//CHECK : if trying to decode file which not exist in cache return null
Bitmap b = decodeFile(f);
if(b!=null)
return b;
// Download image file from web
try {
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();
// Constructs a new FileOutputStream that writes to file
// if file not exist then it will create file
OutputStream os = new FileOutputStream(f);
// See Utils class CopyStream method
// It will each pixel from input stream and
// write pixels to output stream (file)
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
//Now file created and going to resize file with defined height
// Decodes image and scales it to reduce memory consumption
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 consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
// Set width/height of recreated image
final int REQUIRED_SIZE=85;
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 current scale values
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
//Check url is already exist in imageViews MAP
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
// Show bitmap on UI
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
//Clear cache directory downloaded images and stored data in maps
memoryCache.clear();
fileCache.clear();
}
}
File : FileCache.java
package com.androidexample.lazyimagedownload;
import java.io.File;
import android.content.Context;
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir at SDCARD to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
{
//if SDCARD is mounted (SDCARD is present on device and mounted)
cacheDir = new File(
android.os.Environment.getExternalStorageDirectory(),"LazyList");
}
else
{
// if checking on simulator the create cache dir in your application context
cacheDir=context.getCacheDir();
}
if(!cacheDir.exists()){
// create cache dir in your application context
cacheDir.mkdirs();
}
}
public File getFile(String url){
//Identify images by hashcode or encode by URLEncoder.encode.
String filename=String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
// list all files inside cache directory
File[] files=cacheDir.listFiles();
if(files==null)
return;
//delete all cache directory files
for(File f:files)
f.delete();
}
}
Download here click Fireandroids
Hi... i cannot download your project link file.... do you have other direct link? and your tutorial missing code for Memory cache
ReplyDelete