For clients-server-side applications, getting pictures remotely is a common feature. and picture resources tend to consume a larger flow, for applications, if the problem is not handled well, it will make users very crash, unknowingly mobile phone traffic ran out, and other users found that your application consumed his mobile phone traffic , then imagine your application will face what kind of fate.
Another problem is load speed, if the application of the picture loading slow, then the user will also wait until the crash.
So how to deal with the acquisition and management of picture resources?
- * Asynchronous Download
- * Local Cache
1, Asynchronous Download:
As we all know, the UI thread in the Android application will not respond to 5 seconds to throw a no response exception, for remote access to large resources, this exception is very easy to throw out, then how to avoid this problem. There are two ways to do this with Android:
Starts a new thread to fetch the resource, completes the message through the handler mechanism, and processes the message in the UI thread to get the picture in the asynchronous thread and then update the UI thread through the handler message.
Use the Asynctask provided in Android to do this.
The specific approach is not introduced here, check the API can be, or Google, Baidu under. This is mostly local caching.
2. Local cache:
For picture resources, it's impossible to get apps to download remotely (ListView) every time you get them. This will waste resources, but you can not let all the picture resources are put into memory (although this load will be faster), because the image resources tend to occupy a lot of memory space, easily lead to oom. So if the downloaded picture is saved to SDcard, next time directly from SDcard to get it? This is also a practice, I looked at, there are many applications in this way. Some algorithms, such as LRU, can ensure that the space occupied by SDcard is only a small part, so as to ensure the loading of pictures, save the flow, and make the SDcard space only occupy a small part. Alternatively, the resource is stored directly in memory, and then the expiration time and the LRU rule are set.
SDcard Save:
to open up a certain space on the sdcard, it is necessary to determine whether the remaining space on the sdcard is enough, if enough can open up some space, such as 10M
When you need to get a picture, look it up from the directory on the SDcard, and if you find it, use the picture and update the last time the picture was used. If not found, through the URL to download to the server side to download the picture, if the download succeeds, put into the sdcard, and use, if failed, there should be a retry mechanism. Like 3 times.
After the successful download to the SDcard, you need to determine whether 10M space has been used up, if not used up to save, if the space is not enough on the basis of the LRU rule to remove some of the recent user resources.
Key code:
Save the picture to the SD card:
private void Savebmptosd (Bitmap BM, stringurl) {
if (BM = null) {
LOG.W (TAG, "trying to savenull Bitmap");
return;
}
Determine the space on the SDcard
if (Free_sd_space_needed_to_cache >freespaceonsd ()) {
LOG.W (TAG, "low free spaces ONSD, do not Cache ");
return;
}
String filename =converturltofilename (URL);
String dir = getdirectory (filename);
File File = new file (dir + "/" + filename);
try {
file.createnewfile ();
OutputStream OutStream = newfileoutputstream (file);
Bm.compress (Bitmap.CompressFormat.JPEG, 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");
}
To compute the space on the SDcard:
/**
* Compute the remaining space on SDcard
* @return * *
private int freespaceonsd () {
Statfs stat = Newstatfs ( Environment.getexternalstoragedirectory (). GetPath ());
Double sdfreemb = (double) stat.getavailableblocks () * (double) stat.getblocksize ())/MB;
return (int) sdfreemb;
}
Modify the file's last modified time:
/**
* Modify the file's last modified time
* @param dir
* @param
fileName
/private void Updatefiletime (String dir, String fileName) {
File File = new file (dir,filename);
Long Newmodifiedtime =system.currenttimemillis ();
File.setlastmodified (Newmodifiedtime);
}
Local cache optimization:
/** * Calculates the size of the file in the storage directory, when the total size of the file is larger than the specified cache_size or sdcard remaining space is less than the Free_sd_space_needed_to_cache rule * then delete 40% files not recently used * @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 (). Contains (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 expired file * @param dirpath * @param filename/private void Removeexpiredcache (StringDirpath, String filename) {File File = new file (dirpath,filename);
if (System.currenttimemillis ()-file.lastmodified () > Mtimediff) {log.i (TAG, "clear some expiredcache files");
File.delete ();
}
}
Use time to sort files:
/**
* TODO Sort by the last modified time of the file */
Classfilelastmodifsort implements comparator<file>{public
int Compare (file arg0, file arg1) {
if (arg0.lastmodified () >arg1.lastmodified ()) {return
1;
} else if (arg0. LastModified () ==arg1.lastmodified ()) {return
0;
} else {
return-1;
}
}}
Memory Save:
Save in memory, you can only save a certain amount, and can not always go inside, you need to set the data expiration time, LRU algorithm. One way to do this is to put the commonly used data in a cache (a) and to put it in a different cache (B). When you want to get the data, first get it from a, if it doesn't exist then go to B to get it. The data in B is mainly the data from the LRU in a, where the memory recycle is mainly for B memory, which keeps the data in a can be hit effectively.
First define a cache
Private Final hashmap<string, Bitmap>mhardbitmapcache = new linkedhashmap<string, bitmap> (HARD_CACHE_ CAPACITY/2, 0.75f, True) {
@Override
protected booleanremoveeldestentry (linkedhashmap.entry<string, Bitmap> eldest) {
if (size () >hard_cache_capacity) {
//when the size of the map is greater than 30 o'clock, place the recently infrequently used key in the Msoftbitmapcache. Thus ensuring the efficiency of Mhardbitmapcache
Msoftbitmapcache.put (Eldest.getkey (), newsoftreference<bitmap> ( Eldest.getvalue ()));
return true;
} else return
false;
To define the B cache again:
/** * When the key of the Mhardbitmapcache is greater than 30, the key that has not been used recently is put into this cache according to the LRU algorithm. *bitmap used SoftReference, when the memory space is insufficient, this cache in bitmap will be garbage collected/private final staticconcurrenthashmap<string, softreference<bitmap>> Msoftbitmapcache =new concurrenthashmap<string,softreference<bitmap>>
(HARD_CACHE_CAPACITY/2);
Get data from cache:/** * get picture from cache/Private Bitmap Getbitmapfromcache (stringurl) {//Get first from Mhardbitmapcache cache
Synchronized (Mhardbitmapcache) {final Bitmap Bitmap =mhardbitmapcache.get (URL);
if (bitmap!= null) {//if found, move the element to the front of the linkedhashmap to ensure that it is finally deleted mhardbitmapcache.remove (URL) in the LRU algorithm;
Mhardbitmapcache.put (URL,BITMAP);
return bitmap; }///If not found in Mhardbitmapcache, find softreference<bitmap>bitmapreference in Msoftbitmapcache = MSOFTBITMAPCA
Che.get (URL);
if (bitmapreference!= null) {final Bitmap Bitmap =bitmapreference.get (); if (bitmap!= null) {return Bitmap;
else {msoftbitmapcache.remove (URL);
} return null;
}
If the cache does not exist, you can only go to the server side to download:
/** * Asynchronous Download Picture/class Imagedownloadertask extendsasynctask<string, Void, bitmap> {private static final in
T io_buffer_size= 4 * 1024;
Private String URL;
Private finalweakreference<imageview> imageviewreference;
Public Imagedownloadertask (imageviewimageview) {imageviewreference = newweakreference<imageview> (ImageView); } @Override protected Bitmapdoinbackground (String ... params) {Final androidhttpclient client =android
Httpclient.newinstance ("Android");
url = params[0];
Final HttpGet getrequest = newhttpget (URL);
try {httpresponse response =client.execute (getrequest);
Final int StatusCode =response.getstatusline (). Getstatuscode ();
if (StatusCode!=httpstatus.sc_ok) {LOG.W (TAG, "Download the picture from" +url + "Error!, error code:" + StatusCode);
return null;
Final httpentity entity =response.getentity (); if (entity!= null) {InputStream InputStream =null;
OutputStream 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 ();
A 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;
}
There are two ways to do this, and some applications use the thread pool and Message Queuing MQ when downloading, which is more efficient for downloading pictures. Interested students can look down.
Summary: For remote pictures and other relatively large resources must be in the asynchronous thread to get the local cache.
The above is the Android remote capture picture and the local caching method detailed introduction, hope to be helpful to everybody's study.