Android image processing artifact Bitmapfun source analysis

Source: Internet
Author: User
Tags set background

As an Android developer, I believe you are familiar with the picture oom problem, about the image cache and solve Oom open source project is quite a lot, is known to be universal_image_loader and volley, Volley has been introduced in the previous article. Universal_image_loader in the picture cache function is the most powerful, but feel very versatile, so in the project I generally do not like to use Universal_image_loader (because of their own app source very much, Adding these open source libraries is even bigger, prone to problems that cannot be compiled, because Android seems to have a limit on the number of methods in an application, which seems to be 655**, and I can't remember exactly how much.

About processing the picture cache, I contacted two player projects, using Bitmapfun,bitmapfun is Google for Android Development provides a training tutorial, since it is provided by Google, Then I think as a qualified Android developer it is necessary to learn, and Bitmapfun is very simple, basically can meet the needs of the image cache processing in our project.

For open source projects, I usually seldom learn at the application level, because there are quite a lot of blogs about how to use an open source project, and it's very detailed, and for most open source projects it comes with sample, so if you want to learn how to use an open source project, Do a good study of sample, but I always think, familiar with the classic open source project source code is kingly. OK nonsense not much to say, we began to learn Bitmapfun source bar.

1. Bitmapfun structure
The structure of Bitmapfun and other open source libraries is slightly different, as it is just Google's training tutorial, so bitmapfun and its sample are placed in a project, the structure is as follows: The above section is the application of Bitmapfun, The following section is the source code of Bitmapfun.

2. Introduction of related classes
One of the most important classes in Bitmapfun is Imagefetcher, which is called the LoadImage method, but the class is inherited Imageresizer, and Imageresizser is inherited Imageworker, So let's start learning from Imageworker.

imageworker.java/** This class is used to encapsulate the loading process of a picture, including the use of loading from the cache */public abstract class Imageworker {private static final String TAG = imageworker;//This variable is used for animation effects, no practical purpose private static final int fade_in_time = 200;//cache, including disk cache and memory cache private Imagecache Mima gecache;//Create the parameters required for caching private imagecache.imagecacheparams mimagecacheparams;//during the loading process, the ImageView display the picture private Bitmap Mloa dingbitmap;//whether to use the gradient effect private Boolean mfadeinbitmap = true;//whether to quit the task prematurely, if true, then the picture request is not displayed after the private Boolean mexit    Tasksearly = false;//Whether to pause the task protected Boolean mpausework = false;    Private Final Object Mpauseworklock = new Object ();    protected Resources mresources;    private static final int message_clear = 0;    private static final int message_init_disk_cache = 1;    private static final int message_flush = 2;    private static final int message_close = 3;    Protected Imageworker (Context context) {mresources = Context.getresources (); }/** * Request a picture of the interface * @param picture URL * @param to display this pictureImageView */public void LoadImage (Object data, ImageView ImageView) {if (data = = null) {retur        N } bitmapdrawable value = null;//If the cached object is not empty, then the object is read from the memory cache if (Mimagecache! = null) {value = Mimagec        Ache.getbitmapfrommemcache (string.valueof (data));        } if (value! = NULL) {///memory cache hit, then direct display of imageview.setimagedrawable (value); } else if (cancelpotentialwork (data, ImageView)) {//memory cache is not hit, then create a picture request task, and ImageView as the parameter final Bitmapworkerta SK task = new Bitmapworkertask (ImageView),//asyncdrawable is the bitmapdrawable subclass, mainly used to store the weak application of the current task final asyncdrawable asyncdrawable = new Asyncdrawable (mresources, Mloadingbitmap, Task);//Set asyncdrawable to ImageView so IMA            Geview and the current mission of one by one correspond to imageview.setimagedrawable (asyncdrawable); Calling Asynctask's Executeonexecutor method, this asynctask is somewhat different from the asynctask of the Android system, but uses the same task.executeonexecutor (Asynctas K.dual_Thread_executor, data); }}/** * Set the default picture during loading * * @param bitmap */public void Setloadingimage (bitmap bitmap) {m    Loadingbitmap = bitmap; /** * Set the local picture as the default picture * * @param resId */public void setloadingimage (int resId) {Mloadingbit    Map = Bitmapfactory.decoderesource (mresources, resId); }/** * Adds a buffer object that requires a child thread to complete when creating the disk cache * @param fragmentmanager * @param cacheparams the cache parameters to use     For the image cache.        */public void Addimagecache (Fragmentmanager fragmentmanager, Imagecache.imagecacheparams cacheparams) {        Mimagecacheparams = Cacheparams; Mimagecache = Imagecache.getinstance (Fragmentmanager, mimagecacheparams);//completion of disk cache initialization new Cacheasynctask (). Execute (M    Essage_init_disk_cache);     }/** * Adds a {@link Imagecache} to the {@link Imageworker} to handle disk and memory bitmap * caching. * @param activity * @param diskcachedirectoryname SEE * {@link imagecache.imagecacheparams#imagecacheparams (Context, String)}.  */public void Addimagecache (fragmentactivity activity, String diskcachedirectoryname) {mimagecacheparams = new        Imagecache.imagecacheparams (activity, diskcachedirectoryname);        Mimagecache = Imagecache.getinstance (Activity.getsupportfragmentmanager (), mimagecacheparams);    New Cacheasynctask (). Execute (Message_init_disk_cache);    }/** * Sets whether to use the gradient effect */public void Setimagefadein (Boolean fadeIn) {mfadeinbitmap = FadeIn;        }//whether to quit the task in advance public void Setexittasksearly (Boolean exittasksearly) {mexittasksearly = exittasksearly;    Setpausework (FALSE); }/** * Subclasses should override this to define any processing or work on must happen to produce * the FINA L Bitmap. This is executed in a background thread and is long running.     For * example, you could resize a large bitmap here, or pulling down an image from the network.     ** @param data to identify which image to process, as provided by * {@link imageworker#loadimage (Ob    Ject, ImageView)} * @return the processed bitmap */protected abstract bitmap Processbitmap (Object data);     /** * @return The {@link Imagecache} object currently being used by this imageworker.    */protected Imagecache Getimagecache () {return mimagecache;     }/** * Cancels any pending work attached to the provided ImageView. * @param imageView */public static void Cancelwork (ImageView imageView) {//Find a task through ImageView, why can I find it?        Because ImageView and task one by one correspond to final bitmapworkertask Bitmapworkertask = Getbitmapworkertask (ImageView);//If the task is not empty, then cancel            if (bitmapworkertask! = null) {Bitmapworkertask.cancel (true);                if (buildconfig.debug) {final Object bitmapData = Bitmapworkertask.data;            LOG.D (TAG, cancelwork-cancelled work for + bitmapData); }        }    }   /** * Returns True if the current work has been canceled or if there is no work in * progress on this image VI     ew. * Returns False if the work in progress deals with the same data.     The work isn't * stopped in the. */public static Boolean cancelpotentialwork (Object data, ImageView ImageView) {//Find task final Bitmap through ImageView        Workertask bitmapworkertask = Getbitmapworkertask (ImageView); if (bitmapworkertask! = null) {//If the found task is not null and the URL of the task is the same as the given URL, then the task is canceled final Object bitmapData = Bitmapwor            Kertask.data;                if (BitmapData = = NULL | |!bitmapdata.equals (DATA)) {Bitmapworkertask.cancel (true);                if (buildconfig.debug) {log.d (TAG, cancelpotentialwork-cancelled work for + data);                }} else {//the same work was already in progress.            return false;    }} return true; }/** * Find corresponding by IamgeviewTask */private static Bitmapworkertask Getbitmapworkertask (ImageView ImageView) {if (ImageView! = null) {            Final drawable drawable = imageview.getdrawable ();                if (drawable instanceof asyncdrawable) {final asyncdrawable asyncdrawable = (asyncdrawable) drawable;            return Asyncdrawable.getbitmapworkertask ();    }} return null; }/** * An asynchronous task to request a picture, */private class Bitmapworkertask extends Asynctask<object, bitmapdrawable= "" > {/        /request the URL of the picture private Object data;//holds ImageView's weak reference private final weakreference imageviewreference;        Public Bitmapworkertask (ImageView ImageView) {imageviewreference = new WeakReference (ImageView);         }/** * Background processing.                 */@Override protected bitmapdrawable doinbackground (Object ... params) {if (buildconfig.debug) { LOG.D (TAG, Doinbackground-starting work);            } data = Params[0];            Final String datastring = string.valueof (data);            Bitmap Bitmap = null;            Bitmapdrawable drawable = null; If the work is paused and the picture request is not canceled, wait for synchronized (Mpauseworklock) {while (Mpausework &&!isca                    Ncelled ()) {try {mpauseworklock.wait (); } catch (Interruptedexception e) {}}}//if there is a cache and no cancellation, the imageview corresponding task in the current weak reference is self (task), then from the disk cache Read//Why read the disk cache here? Because the disk cache can only be read on an asynchronous thread, Doingbackground is the asynchronous thread that executes if (mimagecache! = null &&!iscancelled () && Getattach Edimageview () = null &&!mexittasksearly) {bitmap = MIMAGECACHE.GETBITMAPFROMD            Iskcache (datastring);            }//If there is no hit, and no cancellation, and the current weak reference in the ImageView corresponding task is self, then request the network picture,//Call the Processbitmap method, this method is an abstract, implemented in Imagefecter if (bitmap = = null &&!iscancelled () && getattachedimageview ()! = null &&!mexittasksearly) {bitmap =            Processbitmap (Params[0]); }//If the bitmap was processed and the image cache is available, then add the processed//bitmap To the cache for a future use. Note we don ' t check if the task was cancelled//here, if it was, and the thread is still running, we may as we ll add the processed//bitmap to our cache as it might is used again in the future if (Bitmap! = Nu LL) {if (Utils.hashoneycomb ()) {//Running on honeycomb or newer, so wrap in a standar                D bitmapdrawable drawable = new Bitmapdrawable (mresources, bitmap);  } else {//Running on gingerbread or older, so wrap in a recyclingbitmapdrawable// Which would recycle automagically drawable = new Recyclingbitmapdrawable (mresourCES, bitmap); }//Add picture to cache if (Mimagecache! = null) {Mimagecache.addbitmaptocache (datastring, drawable)                ;            }} if (Buildconfig.debug) {log.d (TAG, doinbackground-finished work);        } return drawable; }/** * Once the image is processed, associates it to the ImageView */@Override Prot  ected void OnPostExecute (bitmapdrawable value) {//If canceled or exited prematurely, do not display this image, directly set NULL if (IsCancelled () ||            mexittasksearly) {value = null;            } final ImageView ImageView = Getattachedimageview (); if (value! = NULL && ImageView! = null) {if (buildconfig.debug) {log.d (TAG, on                Postexecute-setting bitmap);            }//Displays the picture setimagedrawable (ImageView, value); }} @Override protected voidOncancelled (bitmapdrawable value) {super.oncancelled (value);//The task is canceled and the background thread must be notified to stop waiting for synchronized (Mpau            Seworklock) {mpauseworklock.notifyall (); }} private ImageView Getattachedimageview () {final ImageView ImageView = Imageviewrefere            Nce.get ();            Final Bitmapworkertask bitmapworkertask = Getbitmapworkertask (ImageView);            if (this = = Bitmapworkertask) {return imageView;        } return null; }}/** * for implementing ImageView and task one by one corresponding classes */private static class Asyncdrawable extends Bitmapdrawable {p        Rivate final WeakReference bitmapworkertaskreference;            Public Asyncdrawable (Resources res, Bitmap Bitmap, Bitmapworkertask bitmapworkertask) {super (res, BITMAP);        Bitmapworkertaskreference = new WeakReference (bitmapworkertask); } public Bitmapworkertask Getbitmapworkertask () {RetuRN Bitmapworkertaskreference.get (); }}/** * Display picture, gradient display or normal display * * @param imageView * @param drawable * * private void Setimagedraw Able (ImageView ImageView, drawable drawable) {if (Mfadeinbitmap) {//Transition drawable with a TRANSP Arent drawable and the final drawable final transitiondrawable td = New Transitiondrawable (n EW drawable[] {new Colordrawable (Android.            r.color.transparent), drawable}); Set background to loading bitmap imageview.setbackgrounddrawable (new bitmapdrawable (mRes            Ources, Mloadingbitmap));            Imageview.setimagedrawable (TD);        Td.starttransition (Fade_in_time);        } else {imageview.setimagedrawable (drawable); }    }}


After analyzing the imageworker, we found that in the Imageworker has provided a way to get the network picture LoadImage, when I call this method, the first attempt to get a picture from the memory cache, if the acquisition succeeds, directly return, if not get success, Starts a bitmapworkertask, uses an asynchronous thread to get the picture, in the asynchronous thread, first to disk, if the disk is not fetched, and finally from the network, We found that the image was obtained by calling the Processbitmap method in Bitmapworkertask, but this method is an abstract method that requires subclasses to implement, then we go to its subclass Imageresizer

@Override    protected Bitmap processbitmap (Object data) {        return Processbitmap (Integer.parseint ( String.valueof (data)));    }


It calls another overloaded Processbitmap method, so let's look at another way.

Private Bitmap processbitmap (int resId) {        if (buildconfig.debug) {            log.d (TAG, Processbitmap-  + resId);        }        return Decodesampledbitmapfromresource (mresources, ResId, Mimagewidth,                mimageheight, Getimagecache ());    }


We found that this method is only used to load the local image, and how it is to implement the network image loading, if you read the Imageresizer source, you will find the main functions of Imageresizer This class are as follows:
1. Set the sizse of the display picture
2. Loading pictures from the disk cache

So loading pictures from the network is not the function of this class at all, smart students should immediately think of imagefetcher this class, right! , let's just take a look at the Imagefetcher class.

Private Bitmap Processbitmap (string data) {final string key = Imagecache.hashkeyfordisk (data);        FileDescriptor filedescriptor = null;        FileInputStream fileinputstream = null; Disklrucache.snapshot snapshot;//Check if Mhttpdiskcache has been initialized, it is important to note that        Mhttpdiskcache This disk cache is initialized when Imagefetcher calls Addimagecache, if you do not call addimagecache//then this will block, so that you can not get the picture, the situation also please analyze the code yourself Synchronized (Mhttpdiskcachelock) {//Wait for disk cache to initialize while (Mhttpdiskcachestarti                NG) {try {mhttpdiskcachelock.wait ();                } catch (Interruptedexception e) {}}//the code below is to write a picture from Mhttpdiskcache if (mhttpdiskcache! = null) {                    try {snapshot = Mhttpdiskcache.get (key); if (snapshot = = null) {if (buildconfig.debug) {log.d (TAG, Processbitma                       P, not found in HTTP cache, downloading ...); } disklrucache.editor Editor = Mhttpdiskcache.edit (key);                                    if (editor! = null) {//Download the picture logic here if (Downloadurltostream (data,                            Editor.newoutputstream (Disk_cache_index)) {editor.commit ();                            } else {editor.abort ();                    }} snapshot = Mhttpdiskcache.get (key); } if (snapshot! = null) {FileInputStream = (File                        InputStream) Snapshot.getinputstream (Disk_cache_index);                    FileDescriptor = Fileinputstream.getfd ();                }} catch (IOException e) {log.e (TAG, Processbitmap-+ E);  } catch (IllegalStateException e) {log.e (TAG, Processbitmap-+ E);              } finally {if (FileDescriptor = = NULL && FileInputStream! = null) {                        try {fileinputstream.close ();        } catch (IOException e) {}}}} Bitmap Bitmap = null; if (filedescriptor! = null) {//calls the method in Imageresizer to generate a picture of the Mhttpdiskcache in the specified size bitmap = DECODESAMPLEDBITMAPFR        Omdescriptor (FileDescriptor, Mimagewidth, Mimageheight, Getimagecache ());            } if (FileInputStream! = null) {try {fileinputstream.close ();    } catch (IOException e) {}} return bitmap; /** * Download pictures from the network via HttpURLConnection and write to disk cache * * @param urlstring the URL to fetch * @return true if suc        Cessful, FALSE otherwise */public boolean downloadurltostream (String urlstring, OutputStream outputstream) { DisableconnectionreuseifneceSsary ();        HttpURLConnection urlconnection = null;        Bufferedoutputstream out = null;        Bufferedinputstream in = null;            Try {final URL url = new URL (urlstring);            URLConnection = (httpurlconnection) url.openconnection ();            in = new Bufferedinputstream (Urlconnection.getinputstream (), io_buffer_size);            out = new Bufferedoutputstream (OutputStream, io_buffer_size);            int b;            while ((b = In.read ())! =-1) {out.write (b);        } return true;        } catch (Final IOException e) {log.e (TAG, Error in Downloadbitmap-+ E);            } finally {if (urlconnection! = null) {urlconnection.disconnect ();                } try {if (out! = null) {out.close ();                } if (in = null) {in.close ();      }} catch (Final IOException e) {}}  return false; }


Well, for the entire code logic of Bitmapfun I simply analyzed here, in fact, understand the Bitmapfun code logic, we can completely optimize it, I just put forward a little bit to optimize the place, the optimization of the method to the people to complete it

For example, when the bitmapworkertask gets the picture, it reads the disk cache and then gets it from the network, that is, if it is done in the same thread while reading the local and reading the network picture, there is a possibility that there will be a problem. Local pictures exist but can not be loaded out: For example: In the case of bad network conditions, the previous five picture requests just ran out of all the threads, because the network condition is not good, has not returned, and the sixth picture just has the cache, then it is unable to load out, because there is no thread, So the solution is to learn the solution in volley (my previous article for volley already introduced), to have one thread specialize in local images, and other threads to work with network pictures.

Just write here, if you have nothing to read or I wrote the wrong, welcome message .....

Android image processing artifact Bitmapfun source analysis

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.