Android photo wall full version, perfect combination of LruCache and DiskLruCache

Source: Internet
Author: User

Android photo wall full version, perfect combination of LruCache and DiskLruCache

 

In the previous article, we learned the concept and basic usage of DiskLruCache, but it is obviously not enough to grasp the theoretical knowledge. In this article, we will continue to provide an advanced level, let's take a look at how to properly use DiskLruCache in practice. If you are not familiar with DiskLruCache usage, refer to my previous article.Complete parsing of Android DiskLruCache and best solution for hard disk cache.

In fact, in the real project practice, if you only use hard disk cache, the program has a short board. However, if you only use the memory cache, the program will certainly have great defects. Therefore, an excellent program will inevitably combine the memory cache and the hard disk cache. In this article, we will take a look at how to perfectly combine LruCache and DiskLruCache.

InAndroid photo wall application implementation, no longer afraid of crashesIn this article, I wrote a photo wall application, but I only used the memory cache. Today, we will expand this example to create a full photo wall.

Let's get started and create an Android project named PhotoWallDemo. Here I am using the Android 4.0 API. Create a libcore. io package and copy the DiskLruCache. java file to the package. This completes the preparation.

Next, we need to consider the problem of image source. For simplicity, I still want to upload all the Images to my CSDN album and then create an Images class, configure the URLs of images in all albums. The Code is as follows:

public class Images {public final static String[] imageThumbUrls = new String[] {http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg,http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg,http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg,http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg,http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg,http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg,http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg,http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg,http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg,http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg,http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg,http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg,http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg,http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg,http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg,http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg,http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg,http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg,http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg,http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg,http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg,http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg,http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg,http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg,http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg,http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg,http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg,http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg,http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg,http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg,http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg,http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg,http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg,http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg,http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg,http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg,http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg,http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg,http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg,http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg,http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg,http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg,http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg,http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg,http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg,http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg,http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg,http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg,http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg,http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg,http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg,http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg,http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg,http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg,http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg,http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg,http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg,http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg,http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg,http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg,http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg,http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg,http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg,http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg,http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg,http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg,http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg,http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg,http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg,http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg,http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg,http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg,http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg,http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg,http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg,http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg,http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg,http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg,http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg,http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg,http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg,http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg,http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg,http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg,http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg};}
After the image source is set, we need a GridView to display each image on the photo wall. Open or modify the code in activity_main.xml as follows:
     
      
  
 
It's easy, just write a GridView in LinearLayout. Next, we need to define the layout of each sub-View in the GridView, create a new photo_layout.xml layout, and add the following code:
     
  
 
It is still very simple. There is only one ImageView control in the photo_layout.xml layout, which is used to display images. In this way, we can write all the layout files.

 

Next, create a PhotoWallAdapter as the GridView Adapter. The Code is as follows:

Public class PhotoWallAdapter extends ArrayAdapter
 
  
{/*** Record all tasks that are being downloaded or waiting for download. */Private Set
  
   
TaskCollection;/*** core class of image caching technology, used to cache all downloaded images. When the program memory reaches the set value, the latest images will be removed. */Private LruCache
   
    
MMemoryCache;/*** core category of image hard disk cache. */Private DiskLruCache mDiskLruCache;/* GridView instance */private GridView mPhotoWall;/*** records the height of each subitem. */Private int mItemHeight = 0; public PhotoWallAdapter (Context context, int textViewResourceId, String [] objects, GridView photoWall) {super (context, textViewResourceId, objects); mPhotoWall = photoWall; taskCollection = new HashSet
    
     
(); // Get the maximum available memory of the application int maxMemory = (int) Runtime. getRuntime (). maxMemory (); int cacheSize = maxMemory/8; // set the image cache size to 1/8 mMemoryCache = new LruCache of the maximum available memory of the program
     
      
(CacheSize) {@ Overrideprotected int sizeOf (String key, Bitmap bitmap) {return bitmap. getByteCount () ;}}; try {// obtain the image cache path File cacheDir = getDiskCacheDir (context, thumb); if (! CacheDir. exists () {cacheDir. mkdirs ();} // create a DiskLruCache instance and initialize the cache data mDiskLruCache = DiskLruCache. open (cacheDir, getAppVersion (context), 1, 10*1024*1024);} catch (IOException e) {e. printStackTrace () ;}@ Overridepublic View getView (int position, View convertView, ViewGroup parent) {final String url = getItem (position); View view; if (convertView = null) {view = LayoutInflater. from (getContext ()). infla Te (R. layout. photo_layout, null);} else {view = convertView;} final ImageView imageView = (ImageView) view. findViewById (R. id. photo); if (imageView. getLayoutParams (). height! = MItemHeight) {imageView. getLayoutParams (). height = mItemHeight;} // set a Tag for the ImageView to ensure that the imageView is not in disorder during asynchronous image loading. setTag (url); imageView. setImageResource (R. drawable. empty_photo); loadBitmaps (imageView, url); return view;}/*** stores an image in LruCache. ** @ Param key * The LruCache key. the URL of the image is entered here. * @ Param bitmap * The LruCache key. Here, the Bitmap object downloaded from the network is passed in. */Public void addBitmapToMemoryCache (String key, Bitmap bitmap) {if (getBitmapFromMemoryCache (key) = null) {mMemoryCache. put (key, bitmap) ;}}/*** gets an image from LruCache. If it does not exist, null is returned. ** @ Param key * The LruCache key. the URL of the image is entered here. * @ Return corresponds to the Bitmap object of the Input key, or null. */Public Bitmap getBitmapFromMemoryCache (String key) {return mMemoryCache. get (key) ;}/ *** load the Bitmap object. This method checks the Bitmap objects of ImageView visible on all screens in LruCache. * If any Bitmap object of ImageView is not in the cache, an asynchronous thread is enabled to download the image. */Public void loadBitmaps (ImageView imageView, String imageUrl) {try {Bitmap bitmap = getBitmapFromMemoryCache (imageUrl); if (bitmap = null) {BitmapWorkerTask task = new bitmapworkertask(%%%%taskcollection.add(task%%task.exe cute (imageUrl);} else {if (imageView! = Null & bitmap! = Null) {imageView. setImageBitmap (bitmap) ;}} catch (Exception e) {e. printStackTrace () ;}}/*** cancels all tasks that are being downloaded or waiting for download. */Public void cancelAllTasks () {if (taskCollection! = Null) {for (BitmapWorkerTask task: taskCollection) {task. cancel (false) ;}}/ *** obtain the path address of the hard disk cache based on the passed uniqueName. */Public File getDiskCacheDir (Context context, String uniqueName) {String cachePath; if (Environment. MEDIA_MOUNTED.equals (Environment. getExternalStorageState () |! Environment. isExternalStorageRemovable () {cachePath = context. getExternalCacheDir (). getPath ();} else {cachePath = context. getCacheDir (). getPath ();} return new File (cachePath + File. separator + uniqueName);}/*** get the version number of the current application. */Public int getAppVersion (Context context) {try {PackageInfo info = context. getPackageManager (). getPackageInfo (context. getPackageName (), 0); return info. versionCode;} catch (NameNotFoundException e) {e. printStackTrace ();} return 1;}/*** sets the height of the item subitem. */Public void setItemHeight (int height) {if (height = mItemHeight) {return;} mItemHeight = height; policydatasetchanged ();} /*** use the MD5 Algorithm to encrypt the Input key and return it. */Public String hashKeyForDisk (String key) {String cacheKey; try {final MessageDigest mDigest = MessageDigest. getInstance (MD5); mDigest. update (key. getBytes (); cacheKey = bytesToHexString (mDigest. digest ();} catch (NoSuchAlgorithmException e) {cacheKey = String. valueOf (key. hashCode ();} return cacheKey;}/*** synchronize cache records to the journal File. */Public void fluchCache () {if (mDiskLruCache! = Null) {try {mDiskLruCache. flush ();} catch (IOException e) {e. printStackTrace () ;}} private String bytesToHexString (byte [] bytes) {StringBuilder sb = new StringBuilder (); for (int I = 0; I <bytes. length; I ++) {String hex = Integer. toHexString (0xFF & bytes [I]); if (hex. length () = 1) {sb. append ('0');} sb. append (hex);} return sb. toString ();}/*** the task of downloading images asynchronously. ** @ Author guolin */class BitmapWorkerTask extends AsyncTask
      
        {/*** Image URL */private String imageUrl; @ Overrideprotected Bitmap doInBackground (String... params) {imageUrl = params [0]; FileDescriptor fileDescriptor = null; FileInputStream fileInputStream = null; Snapshot snapShot = null; try {// generate the keyfinal String key = hashKeyForDisk (imageUrl) corresponding to the image URL; // find the cache snapShot = mDiskLruCache corresponding to the key. get (key); if (snapShot = null) {// if the corresponding cache is not found, request data from the network and write the DiskLruCac He. Editor editor = mDiskLruCache. edit (key); if (editor! = Null) {OutputStream outputStream = editor. newOutputStream (0); if (downloadUrlToStream (imageUrl, outputStream) {editor. commit ();} else {editor. abort () ;}// after the cache is written, find the cache snapShot = mDiskLruCache corresponding to the key again. get (key) ;}if (snapShot! = Null) {fileInputStream = (FileInputStream) snapShot. getInputStream (0); fileDescriptor = fileInputStream. getFD () ;}// resolve the cached data to the Bitmap object Bitmap bitmap = null; if (fileDescriptor! = Null) {bitmap = BitmapFactory. decodeFileDescriptor (fileDescriptor);} if (bitmap! = Null) {// Add the Bitmap object to the memory cache. addBitmapToMemoryCache (params [0], bitmap);} return bitmap;} catch (IOException e) {e. printStackTrace ();} finally {if (fileDescriptor = null & fileInputStream! = Null) {try {fileInputStream. close () ;}catch (IOException e) {}} return null ;}@ Overrideprotected void onPostExecute (Bitmap bitmap) {super. onPostExecute (bitmap); // locate the corresponding ImageView Control Based on the Tag and display the downloaded image. ImageView imageView = (ImageView) mPhotoWall. findViewWithTag (imageUrl); if (imageView! = Null & bitmap! = Null) {imageView. setImageBitmap (bitmap);} taskCollection. remove (this);}/*** create an HTTP request and obtain a Bitmap object. ** @ Param imageUrl * URL of the image * @ return resolved Bitmap object */private boolean downloadUrlToStream (String urlString, OutputStream outputStream) {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 (), 8 * 1024); out = new BufferedOutputStream (outputStream, 8*1024); int B; while (B = in. read ())! =-1) {out. write (B);} return true;} catch (final IOException e) {e. printStackTrace ();} finally {if (urlConnection! = Null) {urlConnection. disconnect ();} try {if (out! = Null) {out. close () ;}if (in! = Null) {in. close () ;}catch (final IOException e) {e. printStackTrace () ;}} return false ;}}}
      
     
    
   
  
 

 

The Code is a little long. Let's analyze it a little bit. First, in the PhotoWallAdapter constructor, We initialized the LruCache class, set the memory cache capacity to 1/8 of the maximum available memory of the program, and then called the DiskLruCache open () method To create an instance and set the hard disk cache capacity to 10 MB, so that we can complete the initialization of LruCache and DiskLruCache.

In the getView () method, we set a unique Tag for each ImageView. This Tag is used to retrieve the ImageView accurately later, otherwise, the asynchronous image loading may be out of order. The loadBitmaps () method is called at the end of the getView () method. The specific logic for loading images is executed here.

Go to the loadBitmaps () method and you can see that the getBitmapFromMemoryCache () method is called to obtain the cache from the memory. If yes, the setImageBitmap () method of ImageView is called directly () method to display the image on the interface. If no image is obtained in the memory, enable a BitmapWorkerTask task to asynchronously load the image.

In the doInBackground () method of BitmapWorkerTask, We flexibly use the various usage of DiskLruCache learned in the previous article. First, generate the corresponding MD5 key based on the image URL, and then call the get () method of DiskLruCache to obtain the hard disk cache. If not, request the image from the network and write it to the hard disk cache, resolve the Bitmap object and add it to the memory cache. Finally, display the Bitmap object on the interface. This completes the entire process.

Next, let's analyze the above process. Each time an image is loaded, it is read in the memory cache first. If the image cannot be read, it is read in the hard disk cache, if the hard disk cache still cannot be read, the original data will be requested from the network. Whether it is obtained from the hard disk cache or from the network, the data should be added to the memory cache after it is read, so that we can quickly read the image from the memory the next time we read it, if the image is removed from the memory, repeat the above process.

In this way, we can combine LruCache and DiskLruCache perfectly. Next, you need to write MainActivity code, which is very simple, as shown below:

Public class MainActivity extends Activity {/*** is used to display the GridView */private GridView mPhotoWall of the photo wall;/*** GridView adapter */private PhotoWallAdapter mAdapter; private int mImageThumbSize; private int mImageThumbSpacing; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mImageThumbSize = getResources (). getDimensionPixelSize (R. dimen. image_thumbnail_size); mImageThumbSpacing = getResources (). getDimensionPixelSize (R. dimen. image_thumbnail_spacing); mPhotoWall = (GridView) findViewById (R. id. photo_wall); mAdapter = new PhotoWallAdapter (this, 0, Images. imageThumbUrls, mPhotoWall); mPhotoWall. setAdapter (mAdapter); mPhotoWall. getViewTreeObserver (). addOnGlobalLayoutListener (new ViewTreeObserver. onGlobalLayoutListener () {@ Overridepublic void onGlobalLayout () {final int numColumns = (int) Math. floor (mPhotoWall. getWidth ()/(mImageThumbSize + mImageThumbSpacing); if (numColumns> 0) {int columnWidth = (mPhotoWall. getWidth ()/numColumns)-mImageThumbSpacing; mAdapter. setItemHeight (columnWidth); mPhotoWall. getViewTreeObserver (). removeGlobalOnLayoutListener (this) ;}}) ;}@ Overrideprotected void onPause () {super. onPause (); mAdapter. fluchCache () ;}@ Overrideprotected void onDestroy () {super. onDestroy (); // end all download tasks mAdapter when you exit the program. cancelAllTasks ();}}

 

In the above Code, we use getViewTreeObserver () to listen to the layout events of the View. After the layout is complete, we will re-Modify the height of the neutron View in the GridView, to ensure that the width and height of the sub-View can be consistent.

 

The AndroidManifest. xml file has not been completed yet. You must configure the AndroidManifest. xml file and add the corresponding permissions as follows:

     
      
       
                            
                                     
       
      
                 
    
   
  
 

 

Okay, all the code is here. Let's run it. The effect is shown in:

For the first time, it was a little slow to request images from the network, but loading the images will be very fast and slide smoothly.

Finally, check whether these images are properly cached at the specified address and go to the/sdcard/Android/data/cache/thumb path, as shown in:

 

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.