1. Introduction
Currently, images are inevitably used in Android applications. Some images can be changed and need to be pulled from the network at each startup, there are many such scenarios in advertising spaces and pure image applications (such as Baidu meipai.
Now there is a problem: If you pull images from the network every time you start, it will inevitably consume a lot of traffic. In the current situation, for non-WiFi users, the traffic is still very expensive. For a very traffic-consuming application, the number of users must be affected. Of course, I think that an application like Baidu meide must also have its internal image Cache Policy. In short, image caching is very important and necessary.
2. Image Cache principles
It is not difficult to implement image caching. A corresponding cache policy is required. Here I use the memory-file-network layer-3 cache mechanism, in which the memory cache includes the strong reference cache and soft reference cache (softreference). In fact, the network is not a cache, you can also drag it to the cache hierarchy. When pulling images from the network based on the URL, first find the image from the memory. If the image does not exist in the memory, find the image from the cache file. If the image does not exist in the cache file, then pull the image from the network through an HTTP request. In key-value pairs, the cached key of the image is the hash value of the image URL, and the value is bitmap. Therefore, according to this logic, as long as a URL has been downloaded, its image will be cached.
For softreference of objects in Java, if an object has soft references and the memory space is sufficient, the zookeeper recycler will not recycle it. If the memory space is insufficient, the memory of these objects will be recycled. The object can beProgram. Soft references can be used to implement memory-sensitive high-speed cache. Using Soft references can prevent memory leakage and enhance program robustness.
SlaveCodeAn imagemanager is used to manage and cache images. The function interface is public void loadbitmap (string URL, Handler handler). The URL is the image address to download, handler is the callback after the image is successfully downloaded. It processes the message in handler, and the message contains the image information and bitmap object. Imagememorycache, imagefilecache, and lrucache used in imagemanagerCache) Will be in the futureArticle.
3. Code imagemanager. Java
/** Image management * gets images asynchronously and directly calls the LoadImage () function. This function determines whether to obtain images synchronously from the cache or from the network. It directly calls the getbitmap () function, this function automatically determines whether to load images from the cache or the Network * only obtains images from the local device, calls getbitmapfromnative () * to load images only from the network, and CALLS getbitmapfromhttp () **/public class imagemanager implements imanager {private final static string tag = "imagemanager"; private imagememorycache imagemorycache; // memory cache private imagefilecache; // File Cache // list of images being downloaded public static hashmap <stri Ng, Handler> ongoingtaskmap = new hashmap <string, Handler> (); // public static hashmap of the image list to be downloaded <string, Handler> waitingtaskmap = new hashmap <string, handler> (); // Number of threads for simultaneous image download final static int max_download_image_thread = 4; private final handler downloadstatushandler = new handler () {public void handlemessage (Message MSG) {startdownloadnext () ;}}; public imagemanager () {imagememorycache = new imagemememory Cache (); imagefilecache = new imagefilecache ();}/*** get image, multi-thread entry */Public void loadbitmap (string URL, Handler handler) {// get it from the memory cache first and get it to directly load Bitmap bitmap = getbitmapfromnative (URL); If (Bitmap! = NULL) {logger. D (TAG, "loadbitmap: loaded from native"); message MSG = message. obtain (); bundle = new bundle (); bundle. putstring ("url", URL); MSG. OBJ = bitmap; MSG. setdata (bundle); handler. sendmessage (MSG);} else {logger. D (TAG, "loadbitmap: will load by network"); downloadbmp onnewthread (URL, Handler );}} /*** download the image from the new thread */private void downloadbmp onnewthread (final string URL, final Handler Handler) {logger. D (TAG, "ongoingtaskmap 'size =" + ongoingtaskmap. size (); If (ongoingtaskmap. size ()> = max_download_image_thread) {synchronized (waitingtaskmap) {waitingtaskmap. put (URL, Handler) ;}} else {synchronized (ongoingtaskmap) {ongoingtaskmap. put (URL, Handler);} new thread () {public void run () {bitmap BMP = getbitmapfromhttp (URL); // no matter whether the download is successful or not, all are removed from the download queue, and then the business logic determines whether to re-download the image // download the image using httpclientreques T. the reconnection mechanism synchronized (ongoingtaskmap) {ongoingtaskmap. Remove (URL) ;}if (downloadstatushandler! = NULL) {downloadstatushandler. sendemptymessage (0);} message MSG = message. obtain (); MSG. OBJ = BMP; bundle = new bundle (); bundle. putstring ("url", URL); MSG. setdata (bundle); If (handler! = NULL) {handler. sendmessage (MSG );}}}. start () ;}}/*** load a single bitmap from memory, cached files, and network in sequence, regardless of thread issues */Public bitmap getbitmap (string URL) {// obtain the image Bitmap bitmap = imagememorycache from the memory cache. getbitmapfrommemory (URL); If (Bitmap = NULL) {// obtain bitmap = imagefilecache in the file cache. getimagefromfile (URL); If (Bitmap! = NULL) {// Add it to the memory cache imagememorycache. addbitmaptomemory (URL, bitmap);} else {// obtain bitmap = getbitmapfromhttp (URL) ;}} return bitmap ;} /*** obtain bitmap from memory or cache files */Public bitmap getbitmapfromnative (string URL) {Bitmap bitmap = NULL; bitmap = imagememorycache. getbitmapfrommemory (URL); If (Bitmap = NULL) {bitmap = imagefilecache. getimagefromfile (URL); If (Bitmap! = NULL) {// Add it to the memory cache imagememorycache. addbitmaptomemory (URL, bitmap) ;}} return bitmap;}/*** download images over the network, irrelevant to the thread */Public bitmap getbitmapfromhttp (string URL) {bitmap BMP = NULL; try {byte [] tmppicbyte = getimagebytes (URL); If (tmppicbyte! = NULL) {BMP = bitmapfactory. decodebytearray (tmppicbyte, 0, tmppicbyte. length);} tmppicbyte = NULL;} catch (exception e) {e. printstacktrace ();} If (BMP! = NULL) {// Add to the File Cache imagefilecache. savebitmaptofile (BMP, URL); // Add it to the memory cache imagememorycache. addbitmaptomemory (URL, BMP);} return BMP ;} /*** download the linked image resource ** @ Param URL ** @ return image */Public byte [] getimagebytes (string URL) {byte [] PIC = NULL; if (URL! = NULL &&! "". Equals (URL) {requester request = requesterfactory. getrequester (requester. request_remote, requesterfactory. impl_hc); // execute the request myresponse = NULL; myrequest mmyrequest; mmyrequest = new myrequest (); mmyrequest. seturl (URL); mmyrequest. addheader (httpheader. req. accept_encoding, "Identity"); inputstream is = NULL; bytearrayoutputstream baos = NULL; try {myresponse = request.exe cute (mmyrequest); is = m Yresponse. getinputstream (). getimpl (); baos = new bytearrayoutputstream (); byte [] B = new byte [512]; int Len = 0; while (LEN = is. read (B ))! =-1) {baos. write (B, 0, Len); baos. flush ();} PIC = baos. tobytearray (); logger. D (TAG, "icon bytes. length = "+ pic. length);} catch (exception E3) {e3.printstacktrace (); try {logger. E (TAG, "download your cut icon faild and responsecode =" + myresponse. getstatuscode ();} catch (exception E4) {e4.printstacktrace () ;}} finally {try {If (is! = NULL) {is. Close (); is = NULL ;}} catch (exception E2) {e2.printstacktrace () ;}try {If (baos! = NULL) {baos. close (); baos = NULL ;}} catch (exception E2) {e2.printstacktrace ();} Try {request. close () ;}catch (exception E1) {e1.printstacktrace () ;}}return PIC ;}/ *** retrieves the first task waiting for the queue, start to download */private void startdownloadnext () {synchronized (waitingtaskmap) {logger. D (TAG, "begin start next"); iterator iter = waitingtaskmap. entryset (). iterator (); While (ITER. hasnext () {map. entry entry = (map. entry) ITER. next (); Logger. D (TAG, "waitingtaskmap isn't null, url =" + (string) entry. getkey (); If (entry! = NULL) {waitingtaskmap. remove (entry. getkey (); downloadbmp onnewthread (string) entry. getkey (), (handler) entry. getvalue () ;}break ;}} Public String startdownloadnext_forunittest () {string urlstring = NULL; synchronized (waitingtaskmap) {logger. D (TAG, "begin start next"); iterator iter = waitingtaskmap. entryset (). iterator (); While (ITER. hasnext () {map. entry entry = (map. entry) ITER. next (); urlstring = (string) entry. getkey (); waitingtaskmap. remove (entry. getkey (); break;} return urlstring;}/*** convert the image to a rounded corner * @ Param bitmap: The passed bitmap * @ Param pixels: the degree of the rounded corner. The larger the value, larger rounded corner * @ return bitmap: bitmap */public static bitmap toroundcorner (Bitmap bitmap, int pixels) {If (Bitmap = NULL) return NULL; bitmap output = bitmap. createbitmap (bitmap. getwidth (), bitmap. getheight (), config. argb_8888); canvas = new canvas (output); Final int color = 0xff0000242; Final paint = new paint (); Final rect = new rect (0, 0, bitmap. getwidth (), bitmap. getheight (); Final rectf = new rectf (rect); Final float roundpx = pixels; paint. setantialias (true); canvas. drawargb (0, 0, 0, 0); paint. setcolor (color); canvas. drawroundrect (rectf, roundpx, roundpx, paint); paint. setxfermode (New porterduduxfermode (mode. src_in); canvas. drawbitmap (bitmap, rect, rect, paint); Return output;} public byte managerid () {return image_id ;}}