Optimization for loading network resources in Android can be solved using (thread + cache)

Source: Internet
Author: User

There are also a lot of articles on this aspect on the Internet. The basic idea is to solve this problem through thread + cache. Some optimizations are proposed below:
1. Use a thread pool
2. Memory Cache + File Cache
3. In the memory cache, SoftReference is often used on the network to prevent heap overflow. The strict limit here is that only 1/4 of the maximum JVM memory can be used.
4. Scale the downloaded image proportionally to reduce memory consumption.

The specific code is described in. Put the memory cache class code MemoryCache. java:Copy codeThe Code is as follows: <SPAN style = "FONT-SIZE: 18px"> <STRONG> public class MemoryCache {
Private static final String TAG = "MemoryCache ";
// It is a synchronization operation when it is put into the cache.
// The final parameter true of the LinkedHashMap constructor indicates that the elements in the map will be sorted by the number of recent calls, that is, LRU.
// The advantage is that if you want to replace the elements in the cache, traverse the least recently used elements to replace them to improve efficiency.
Private Map <String, Bitmap> cache = Collections
. SynchronizedMap (new LinkedHashMap <String, Bitmap> (10, 1.5f, true ));
// The Bytes occupied by the image in the cache. The initial value is 0. This variable strictly controls the heap memory occupied by the cache.
Private long size = 0; // current allocated size
// Maximum heap memory that the cache can only occupy
Private long limit = 1000000; // max memory in bytes
Public MemoryCache (){
// Use 25% of available heap size
SetLimit (Runtime. getRuntime (). maxMemory ()/4 );
}
Public void setLimit (long new_limit ){
Limit = new_limit;
Log. I (TAG, "MemoryCache will use up to" + limit/1024./1024. + "MB ");
}
Public Bitmap get (String id ){
Try {
If (! Cache. containsKey (id ))
Return null;
Return cache. get (id );
} Catch (NullPointerException ex ){
Return null;
}
}
Public void put (String id, Bitmap bitmap ){
Try {
If (cache. containsKey (id ))
Size-= getSizeInBytes (cache. get (id ));
Cache. put (id, bitmap );
Size + = getSizeInBytes (bitmap );
CheckSize ();
} Catch (Throwable th ){
Th. printStackTrace ();
}
}
/**
* Strictly control the heap memory. If the heap memory is exceeded, replace the image cache that is least recently used.
*
*/
Private void checkSize (){
Log. I (TAG, "cache size =" + size + "length =" + cache. size ());
If (size> limit ){
// First traverse the least recently used elements
Iterator <Entry <String, Bitmap> iter = cache. entrySet (). iterator ();
While (iter. hasNext ()){
Entry <String, Bitmap> entry = iter. next ();
Size-= getSizeInBytes (entry. getValue ());
Iter. remove ();
If (size <= limit)
Break;
}
Log. I (TAG, "Clean cache. New size" + cache. size ());
}
}
Public void clear (){
Cache. clear ();
}
/**
* Memory occupied by images
*
* @ Param bitmap
* @ Return
*/
Long getSizeInBytes (Bitmap bitmap ){
If (bitmap = null)
Return 0;
Return bitmap. getRowBytes () * bitmap. getHeight ();
}
} </STRONG> </SPAN>

You can also use SoftReference. The code is much simpler, but I recommend the above method.Copy codeThe Code is as follows: public class MemoryCache {

Private Map <String, SoftReference <Bitmap> cache = Collections
. SynchronizedMap (new HashMap <String, SoftReference <Bitmap> ());
Public Bitmap get (String id ){
If (! Cache. containsKey (id ))
Return null;
SoftReference <Bitmap> ref = cache. get (id );
Return ref. get ();
}
Public void put (String id, Bitmap bitmap ){
Cache. put (id, new SoftReference <Bitmap> (bitmap ));
}
Public void clear (){
Cache. clear ();
}
}

The following is the file cache code FileCache. java:Copy codeThe Code is as follows: public class FileCache {
Private File cacheDir;
Public FileCache (Context context ){
// If there is an SD card, create a LazyList directory on the SD card to store the cached image.
// Put it in the cache directory of the system without an SD card
If (android. OS. Environment. getExternalStorageState (). equals (
Android. OS. Environment. MEDIA_MOUNTED ))
CacheDir = new File (
Android. OS. Environment. getExternalStorageDirectory (),
"LazyList ");
Else
CacheDir = context. getCacheDir ();
If (! CacheDir. exists ())
CacheDir. mkdirs ();
}
Public File getFile (String url ){
// Use the url hashCode as the cached file name
String filename = String. valueOf (url. hashCode ());
// Another possible solution
// String filename = URLEncoder. encode (url );
File f = new File (cacheDir, filename );
Return f;
}
Public void clear (){
File [] files = cacheDir. listFiles ();
If (files = null)
Return;
For (File f: files)
F. delete ();
}
}

Finally, the most important class for loading images is ImageLoader. java:Copy codeThe Code is as follows: public class ImageLoader {
MemoryCache memoryCache = new MemoryCache ();
FileCache fileCache;
Private Map <ImageView, String> imageViews = Collections
. SynchronizedMap (new WeakHashMap <ImageView, String> ());
// Thread Pool
ExecutorService executorService;
Public ImageLoader (Context context ){
FileCache = new FileCache (context );
ExecutorService = Executors. newFixedThreadPool (5 );
}
// When you enter the listview, the default image can be replaced with your own default image.
Final int stub_id = R. drawable. stub;
// The Most Important Method
Public void DisplayImage (String url, ImageView imageView ){
ImageViews. put (imageView, url );
// Search from the memory cache first
Bitmap bitmap = memoryCache. get (url );
If (bitmap! = Null)
ImageView. setImageBitmap (bitmap );
Else {
// If not, enable a new thread to load images.
QueuePhoto (url, imageView );
ImageView. setImageResource (stub_id );
}
}
Private void queuePhoto (String url, ImageView imageView ){
PhotoToLoad p = new PhotoToLoad (url, imageView );
ExecutorService. submit (new PhotosLoader (p ));
}
Private Bitmap getBitmap (String url ){
File f = fileCache. getFile (url );
// First, check the File Cache for any
Bitmap B = decodeFile (f );
If (B! = Null)
Return B;
// Finally download the image from the specified url
Try {
Bitmap bitmap = null;
URL imageUrl = new URL (url );
HttpURLConnection conn = (HttpURLConnection) imageUrl
. OpenConnection ();
Conn. setConnectTimeout (30000 );
Conn. setReadTimeout (30000 );
Conn. setInstanceFollowRedirects (true );
InputStream is = conn. getInputStream ();
OutputStream OS = new FileOutputStream (f );
CopyStream (is, OS );
OS. close ();
Bitmap = decodeFile (f );
Return bitmap;
} Catch (Exception ex ){
Ex. printStackTrace ();
Return null;
}
}
// Decode the image and scale it proportionally to reduce memory consumption. The cache size of each image is limited by the virtual machine.
Private Bitmap decodeFile (File f ){
Try {
// Decode image size
BitmapFactory. Options o = new BitmapFactory. Options ();
O. inJustDecodeBounds = true;
BitmapFactory. decodeStream (new FileInputStream (f), null, o );
// Find the correct scale value. It shocould be the power of 2.
Final int REQUIRED_SIZE = 70;
Int width_tmp = o. outWidth, height_tmp = o. outHeight;
Int scale = 1;
While (true ){
If (width_tmp/2 <REQUIRED_SIZE
| Height_tmp/2 <REQUIRED_SIZE)
Break;
Width_tmp/= 2;
Height_tmp/= 2;
Scale * = 2;
}
// Decode with inSampleSize
BitmapFactory. Options o2 = new BitmapFactory. Options ();
O2.inSampleSize = scale;
Return BitmapFactory. decodeStream (new FileInputStream (f), null, o2 );
} Catch (FileNotFoundException e ){
}
Return null;
}
// Task for the queue
Private class PhotoToLoad {
Public String url;
Public ImageView imageView;
Public PhotoToLoad (String u, ImageView I ){
Url = u;
ImageView = I;
}
}
Class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader (PhotoToLoad photoToLoad ){
This. photoToLoad = photoToLoad;
}
@ Override
Public void run (){
If (imageViewReused (photoToLoad ))
Return;
Bitmap bmp = getBitmap (photoToLoad. url );
MemoryCache. put (photoToLoad. url, bmp );
If (imageViewReused (photoToLoad ))
Return;
BitmapDisplayer bd = new BitmapDisplayer (bmp, photoToLoad );
// Update operations in the UI thread
Activity a = (Activity) photoToLoad. imageView. getContext ();
A. runOnUiThread (bd );
}
}
/**
* Prevent image misplacement
*
* @ Param photoToLoad
* @ Return
*/
Boolean imageViewReused (PhotoToLoad photoToLoad ){
String tag = imageViews. get (photoToLoad. imageView );
If (tag = null |! Tag. equals (photoToLoad. url ))
Return true;
Return false;
}
// Update the interface in the UI thread
Class BitmapDisplayer implements Runnable {
Bitmap bitmap;
PhotoToLoad photoToLoad;
Public BitmapDisplayer (Bitmap B, PhotoToLoad p ){
Bitmap = B;
PhotoToLoad = p;
}
Public void run (){
If (imageViewReused (photoToLoad ))
Return;
If (bitmap! = Null)
PhotoToLoad. imageView. setImageBitmap (bitmap );
Else
PhotoToLoad. imageView. setImageResource (stub_id );
}
}
Public void upload AchE (){
MemoryCache. clear ();
FileCache. clear ();
}
Public static void CopyStream (InputStream is, OutputStream OS ){
Final int buffer_size = 1024;
Try {
Byte [] bytes = new byte [buffer_size];
For (;;){
Int count = is. read (bytes, 0, buffer_size );
If (count =-1)
Break;
OS. write (bytes, 0, count );
}
} Catch (Exception ex ){
}
}
}

The main process is to first look up from the memory cache. If no thread is opened and no search from the File Cache is found, search from the specified url and process bitmap, finally, update the UI using the following method.Copy codeThe Code is as follows: a. runOnUiThread (...);

Basic usage in your program:Copy codeThe Code is as follows: <SPAN style = "FONT-SIZE: 18px"> <STRONG> ImageLoader imageLoader = new ImageLoader (context );
...
ImageLoader. DisplayImage (url, imageView); </STRONG> </SPAN>

For example, if you put it in the getView () method of the adapter of your ListView, it also applies to the GridView.

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.