Android Remote Image Retrieval and local cache

Source: Internet
Author: User
Overview for client-server applications, obtaining images remotely is a commonly used function, and image resources often consume a large amount of traffic. For applications, if the problem cannot be solved, the user will crash and the mobile phone traffic will be used up without knowing it. If the user finds that your application has consumed the mobile phone traffic, you can imagine what fate your application will face. Another problem is the loading speed. If the image loading speed in the application is slow, the user will wait for the crash. So how can we get and manage image resources? Asynchronous download local cache asynchronous download everyone knows that in Android applications, if the UI thread does not respond within 5 seconds, a non-response exception will be thrown. for remote access to large resources, this kind of exception can be easily thrown out, so how can we avoid it. Android provides two methods to do this: Start a new thread to obtain resources, send messages through the handler mechanism, and process messages in the UI thread, the process of obtaining images in an asynchronous thread and updating the UI thread through handler message. Use asynctask provided in Android. The specific method is not described here. You can check the API, or Google or Baidu. The local cache is used here. Local cache for image resources, you cannot allow applications to download images remotely every time they obtain them (listview), which wastes resources, however, you cannot place all image resources in the memory (although loading will be faster), because image resources usually occupy a large amount of memory space, which may easily lead to oom. If the downloaded image is saved to the sdcard, will it be directly obtained from the sdcard next time? This is also a practice. I have read it and many applications adopt this method. Use LRU and so on Algorithm It can ensure that the space occupied by sdcard is only one small part, which not only ensures image loading, but also saves traffic, and makes the space occupied by sdcard only a small part. Another approach is to store resources directly in the memory, and then set the expiration time and LRU rules. Sdcard storage: to open up a certain amount of space on the sdcard, you must first determine whether the remaining space on the sdcard is sufficient. If there is enough space, you can open up some space, for example, 10 m when you need to get an image, find the image from the directory on the sdcard. If the image is found, use the image and update the last time the image was used. If the image cannot be found, use the URL to download the image to the server. If the image is downloaded successfully, put it on the sdcard and use it. If the image fails to be downloaded, A Retry Mechanism should be provided. For example, three times. After the download is successful and saved to the sdcard, You need to determine whether the 10 MB space is used up. If the space is not used up, save it. If the space is insufficient, delete some resources that have not been used recently according to the LRU rule. Key Code : Save the image to private void savebmptosd (Bitmap BM, stringurl) {If (Bm = NULL) {log. W (TAG, "trying to savenull bitmap"); return;} // determine the space if (free_sd_space_needed_to_cache> freespaceonsd () on the sdcard {log. W (TAG, "Low Free Space onsd, do not cache"); return;} string filename = converturltofilename (URL); string dir = getdirectory (filename ); file file = new file (DIR + "/" + filename); try {file. createnew File (); outputstream outstream = newfileoutputstream (File); BM. compress (bitmap. compressformat. JPEG, 100, outstream); outstream. flush (); outstream. close (); log. I (TAG, "image saved tosd");} catch (filenotfoundexception e) {log. W (TAG, "filenotfoundexception");} catch (ioexception e) {log. W (TAG, "ioexception") ;}} Save the image to the SD card/*** calculate the remaining space on the sdcard * @ return */private int freespaceonsd () {statfs stat = Newstatfs (environment. getexternalstoragedirectory (). getpath (); double sdfreemb = (double) stat. getavailableblocks () * (double) stat. getblocksize ()/MB; Return (INT) sdfreemb ;} last modification time of the file/* last modification time of the file * @ Param dir * @ Param filename */private void updatefiletime (string Dir, string filename) {file = new file (Dir, filename); long newmodifiedtime = system. currenttimemillis (); file. setla Stmodified (newmodifiedtime);} Local Cache Optimization/*** calculates the file size in the storage directory, when the total file size is greater than the specified cache_size or the remaining sdcard space is less than the free_sd_space_needed_to_cache limit *, delete the file not used recently * @ Param dirpath * @ Param filename */private void removecache (string dirpath) {file dir = new file (dirpath); file [] files = dir. listfiles (); If (Files = NULL) {return;} int dirsize = 0; For (INT I = 0; I <files. length; I ++) {If (files [I]. getname (). cont Ains (wholesale_conv) {dirsize + = files [I]. length () ;}} if (dirsize> cache_size * MB | free_sd_space_needed_to_cache> freespaceonsd () {int removefactor = (INT) (0.4 * files. length) + 1); arrays. sort (files, newfilelastmodifsort (); log. I (TAG, "Clear some expiredcache Files"); For (INT I = 0; I <removefactor; I ++) {If (files [I]. getname (). contains (wholesale_conv) {files [I]. delete ();}}}} /*** Delete the expired file * @ Param dirpath * @ Param filename */private void removeexpiredcache (stringdirpath, string filename) {file = new file (dirpath, filename ); if (system. currenttimemillis ()-file. lastmodified ()> mtimediff) {log. I (TAG, "Clear some expiredcache Files"); file. delete () ;}} sort objects by time/*** todo sort objects by the last modification time **/classfilelastmodifsort implements comparator <File> {public int compare (Fi Le arg0, file arg1) {If (arg0.lastmodified ()> arg1.lastmodified () {return 1;} else if (arg0.lastmodified () = arg1.lastmodified () {return 0 ;} else {return-1 ;}} memory storage: If it is saved in the memory, it can only save a certain amount, rather than keep it in it, you need to set algorithms such as data expiration time and LRU. Here, you can put commonly used data in one cache (a), but not frequently in another cache (B ). To obtain data, first obtain data from A. If a does not exist, then retrieve data from B. The data in B is mainly from lru in a, and the memory reclaim is mainly for Memory B, so that the data in a can be effectively hit. 1. first define a cache: Private Final hashmap <string, bitmap> mhardbitmapcache = new linkedhashmap <string, bitmap> (hard_cache_capacity/2, 0.75f, true) {@ override protected partition (linkedhashmap. entry <string, bitmap> eldest) {If (SIZE ()> hard_cache_capacity) {// when the size of map is greater than 30, put the key that is not commonly used recently into msoftbitmapcache, this ensures the efficiency of mhardbitmapcache. put (eldest. getkey (), newsoftreference <bitmap> (ELD EST. getvalue (); Return true;} else return false ;}}; 2. then, cache B:/*** when the key of the mhardbitmapcache is greater than 30, the key that has not been used recently is put into the cache according to the LRU algorithm. * Bitmap uses softreference. When the memory space is insufficient, bitmap in the cache will be reclaimed */private final staticconcurrenthashmap <string, softreference <bitmap> msoftbitmapcache = new concurrenthashmap <string, softreference <bitmap> (hard_cache_capacity/2); 3. get data from cache:/*** get image from cache */private bitmap getbitmapfromcache (stringurl) {// get synchronized (mhardbitmapcache) from the cache of mhardbitmapcache first) {final Bitmap bitmap = mhardbitmapcache. ge T (URL); If (Bitmap! = NULL) {// if found, move the element to the very beginning of linkedhashmap to ensure that mhardbitmapcache is finally deleted in the LRU algorithm. remove (URL); mhardbitmapcache. put (URL, bitmap); Return bitmap ;}// if mhardbitmapcache cannot be found, find softreference <bitmap> bitmapreference = msoftbitmapcache in msoftbitmapcache. get (URL); If (bitmapreference! = NULL) {final Bitmap bitmap = bitmapreference. Get (); If (Bitmap! = NULL) {return bitmap;} else {msoftbitmapcache. remove (URL) ;}} return NULL;} 4. if the cache does not exist, you can only download images from the server:/*** download images asynchronously */class imagedownloadertask extendsasynctask <string, void, bitmap> {Private Static final int io_buffer_size = 4*1024; private string URL; private finalweakreference <imageview> imageviewreference; Public imagedownloadertask (imageviewimageview) {imageviewreference = newweakrefe Rence <imageview> (imageview) ;}@ override protected bitmapdoinbackground (string... params) {final androidhttpclient client = androidhttpclient. newinstance ("android"); url = Params [0]; Final httpget getrequest = newhttpget (URL); try {httpresponse response client.exe cute (getrequest); Final int statuscode = response. getstatusline (). getstatuscode (); If (statuscode! = Httpstatus. SC _ OK) {log. W (TAG, "An error occurred while downloading images from" + URL + !, Error Code: "+ statuscode); return NULL;} final httpentity entity = response. getentity (); If (entity! = NULL) {inputstream = NULL; outputstream = NULL; try {inputstream = entity. getcontent (); finalbytearrayoutputstream datastream = new bytearrayoutputstream (); outputstream = newbufferedoutputstream (datastream, io_buffer_size); copy (inputstream, outputstream); outputstream. flush (); Final byte [] DATA = datastream. tobytearray (); Final Bitmap bitmap = bitmapfactory. decodebytearray (Data, 0, Data. Length); Return bitmap;} finally {If (inputstream! = NULL) {inputstream. Close ();} If (outputstream! = NULL) {outputstream. close ();} entity. consumecontent () ;}} catch (ioexception e) {getrequest. abort (); log. W (TAG, "I/O errorwhile retrieving bitmap from" + URL, e);} catch (illegalstateexception e) {getrequest. abort (); log. W (TAG, "incorrect URL:" + URL);} catch (exception e) {getrequest. abort (); log. W (TAG, "error whileretrieving bitmap from" + URL, e);} finally {If (client! = NULL) {client. close () ;}} return NULL ;} are two methods. Some applications use the thread pool and Message Queue MQ during download, which improves the image download efficiency. If you are interested, you can check it out. Summary for relatively large resources such as remote images, you must obtain local cache in asynchronous threads.
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.