I'm hoping I can get some opinions on my implementation of an
ImageCache using SoftReferences and  AsyncTask.  The task of the
ImageCache is to load Bitmaps as they are requested.  From the outside
the Bitmaps are requested using the get method which takes the Uri of
the Bitmap to load, and the ImageView which will eventually be updated
with the Bitmap.
A single thread waits for the requests or jobs as I call them to be
added to a job list.

I have to admit, I'm not the most knowledgable when it comes to
threads, but I think I got the
blocking calls correct.  Hopefully the formatting isn't to bad.


The following call initiates the cache and leaves it waiting for jobs

ImageCache.getInstance().executeLoadImagesTask( context );

a Bitmap is retrieved with the following call

Bitmap bm = ImageCache.getInstance().get( _thumbUri.toString(),
_imgVw );

if the image isn't initially in the cache, a default Bitmap is
returned, then a job is added to the job list.  This job contains the
Uri to the Bitmap to load and the ImageView to update.


public class ImageCache
{
        private static final String LOG_TAG = "ImageCache";
        private static final boolean LOGD = true;

        private static ImageCache _instance = null;
        private final HashMap<String, SoftReference<Bitmap>> _cache;

        private Context _ctx;
        private static Bitmap defaultBitmap;
        private Object _lock;
        private ArrayList<ImageJob> jobs =  new ArrayList<ImageJob>();

        public static ImageCache getInstance()
        {
                if ( _instance == null )
                {
                        _instance = new ImageCache();
                }

                return _instance;
        }

        private ImageCache()
        {
                _lock = new Object();
                _cache = new HashMap<String, SoftReference<Bitmap>>();
        }

        public void executeLoadImagesTask( Context ctx )
        {
                _ctx = ctx;
        defaultBitmap = BitmapFactory.decodeResource( _ctx.getResources
(), R.drawable.camera_icon );
                new LoadImagesTask().execute(null);
        }

        public void put( String key, Bitmap bitmap )
        {
                _cache.put( key, new SoftReference<Bitmap>(bitmap) );
        }

        public void clear()
        {
                _cache.clear();
        }

        public Bitmap get( String imguri, UriImageView viewToUpdate )
        {

                Bitmap bm = null;
                SoftReference<Bitmap> reference = _cache.get(imguri);

                if ( reference != null )
                {
                        bm = reference.get();
                }

                if ( bm == null )
                {
                        bm = defaultBitmap;
                        postJob( new ImageJob( imguri, viewToUpdate ) );
                }

                return bm;
        }


        /**
         * Called after the bitmap has been retrieved from the
         * sdcard
         *
         * @param jobs
         */
        public void addImage( ImageJob... jobs )
        {
                ImageJob job = jobs[0];
                final UriImageView view = job.getViewToUpdate();
                final Bitmap bm = job.getBitmap();
                final Uri imguri = job.getImageUri();

                put( imguri.toString(), bm );

                view.post( new Runnable() {

                        public void run()
                        {
                                view.setImage(imguri, bm);
                        }

                });
        }

        private void dbg( String msg )
        {
                if (LOGD) Log.d( LOG_TAG, msg );
        }


        private void postJob( final ImageJob job )
        {
            dbg( "Thread: " + Thread.currentThread().getName() + "
posting job " + job.getImageUri() );
            synchronized(_lock)
            {
                jobs.add(job);
                _lock.notify();
            }
        }

        private class ImageJob
        {
                private Uri _imageUri;
                private UriImageView _viewToUpdate;
                private Bitmap _bm;

                public ImageJob( Uri imageUri, UriImageView viewToUpdate )
                {
                        _imageUri = imageUri;
                        _viewToUpdate = viewToUpdate;
                }

                public ImageJob( String imageUri, UriImageView viewToUpdate )
                {
                        this( Uri.parse( imageUri ), viewToUpdate );
                }

                public Uri getImageUri()
                {
                        return _imageUri;
                }

                public UriImageView getViewToUpdate()
                {
                        return _viewToUpdate;
                }

                public void setBitmap( Bitmap bm )
                {
                        _bm = bm;
                }

                public Bitmap getBitmap()
                {
                        return _bm;
                }
        }

        private class LoadImagesTask extends AsyncTask<Object, ImageJob,
Integer>
        {
                @Override
                protected Integer doInBackground(Object... params)
                {
                        Thread.currentThread().setName( "LoadImagesTask" );

                        while( true )
                        {
                                int jobsize = 0;

                                synchronized( _lock )
                                {
                                        jobsize = jobs.size();
                                }

                                if ( jobsize > 0 )
                                {
                                        synchronized( _lock )
                                        {
                                                ImageJob job = jobs.remove(0);
                                                dbg( "performing image job " + 
job.getImageUri() );

                                                try
                                                {
                                                    job.setBitmap( 
ImgUtils.buildBitmap(_ctx, job.getImageUri(),
4) );
                                                    onProgressUpdate( job );
                                                }
                                                catch (IOException e)
                                                {
                                                        e.printStackTrace();
                                                }
                                        }
                                }
                                else
                                {
                                        try
                                        {
                                                synchronized( _lock )
                                                {
                                                        dbg( "Thread: " + 
Thread.currentThread().getName() + " waiting
for jobs" );
                                                        _lock.wait();
                                                        dbg( "Thread: " + 
Thread.currentThread().getName() + " got a
job" );
                                                }
                                        }
                                        catch (InterruptedException e)
                                        {
                                                e.printStackTrace();
                                        }
                                }
                        }
                }

            @Override
            public void onProgressUpdate(ImageJob... job)
            {
                addImage( job );
            }

            @Override
            public void onPostExecute(Integer imagesLoaded)
            {
                dbg( "loaded " + imagesLoaded + " images" );
            }

        }
}


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to