First, let me introduce to you Android to use the cache mechanism to achieve file download
When downloading files or browsing files online, or in order to ensure the correctness of file downloads, a caching mechanism is required, and SoftReference is often used to achieve it.
The characteristic of SoftReference is that an instance of it holds a soft reference to a Java object. The existence of the soft reference does not hinder the garbage collection thread from recycling the Java object. That is to say, once SoftReference saves a soft reference to a Java object, before the garbage thread recycles the Java object, the get() method provided by the SoftReference class returns a strong reference to the Java object. Additionally, once the garbage thread recycles the Java object, the get() method will return null. A soft reference can be used in conjunction with a reference queue (ReferenceQueue). If the object referenced by the soft reference is recycled by the garbage collector, the Java virtual machine will add the soft reference to the associated reference queue.
The general caching strategy is:
Level 1 memory cache, Level 2 file cache (the database is also considered file cache), and Level 3 network data
1. Cache strategy for network downloads
Basic strategies for downloading files (pictures, audio, video) on the Internet:
1. Do not download the target file directly. You should use the temp file for transit to ensure the correctness and integrity of the file. The process is as follows:
a) Generate a unique local target file name B with network target file name A
b) Generate a unique local temporary file name T with local target file name B
c) Download the file into T
d) After downloading, verify the correctness and integrity of file T
e) If incorrect or incomplete, delete file T and return false
f) After verification is completed, rename file T or copy to file B
g) The final cleanup site, delete the temporary file T, and after success, return true
2. Try to provide verification of file accuracy and integrity:
a) Correctness: For example, MD5/Hash Code comparison, file format comparison.
b) Integrity: For example, whether the file size is consistent and whether the image data is correct (relevant information is provided in the image file header)
3. Consider whether the files downloaded to the local area need to be processed again, you can think about the following situations:
a) For example, the size of the network source original image is 800*600, and the size we need as a thumbnail is 160*145, so consider cropping the downloaded file and saving it, and delete the source original file directly.
2. File caching strategy:
1. A corresponding I/O key for a unique cache file is required. Generally, hashcode can be used.
2. If it is the same file, at different times, you can consider clearing the local cache first, and then downloading the new cache to the local.
3. The same file can also be timestamped and a unique hashcode can be generated.
4. When generating files slowly, the following comprehensive considerations may be required:
a) Whether sdcard has no space anymore (this requirement exists, but almost no one will consider that it must crash once it occurs).
b) Cache cleaning strategy. Daily and weekly cleaning? Automatically clean up after a threshold is reached? (If there is no cleaning strategy, keep the garbage data as a treasure.
Very SB).
c) Cache the data that is really needed. Don’t realize that external storage is infinite, so you can save everything. You should know that if there are many, there will be many, and if there are many, there will be chaos. There was a colleague who saved hundreds of MB of user data every day (gender, age, contact information, etc. of all users), and all they needed was an active data report for several daily accounts, so he finally cached the daily user analysis report data (only 10 KB).
d) Encrypt the cache file. The easiest way is to remove the file extension, which is also considered encryption. Of course, you can encrypt the server file and then decrypt it in memory. It depends on the project's needs. I don't have enough experience, and I usually change the extension or something.
Below is an introduction to Android asynchronous request image plus level 3 cache
It is very convenient to use frameworks such as xUtils, but today we need to use code to implement the function of bitmapUtils, which is very simple.
1 AsyncTask requests a picture
####AsyncTask
#####AsyncTask is a thread pool + handler encapsulation. The first generic is: the parameter type type of the parameter (which is consistent with doInBackground). The second generic is:
#####The parameter type of the update progress (consistent with onProgressUpdate) The third generic: The parameter type of the return result (consistent with onPostExecute,
###### and doInBackground return types are the same)
See the AsyncTask source code:
public abstract class AsyncTask<Params, Progress, Result> { private static final String LOG_TAG = "AsyncTask"; private static final int CORE_POOL_SIZE = 5; private static final int MAXIMUM_POOL_SIZE = 128; private static final int KEEP_ALIVE = 1; private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + ()); } };
Core thread 5 Maximum thread 128 This is the thread pool of AsyncTask and then sends a message through the handler. It internally instantiates a static custom class InternalHandler. This class is inherited from the Handler. An object called AsyncTaskResult is bound to this custom class. Every time the child thread needs to notify the main thread, it calls sendToTarget to send a message to the handler itself. Then in the handleMessage of the handler, AsyncTaskResult performs different operations according to the type of message (for example, MESSAGE_POST_PROGRESS will update the progress bar, and MESSAGE_POST_CANCEL cancels the task). It is worth mentioning that these operations are performed in the UI thread, which means that once the child thread needs to interact with the UI thread, the handler object is automatically called internally and placed in the main thread.
private static final InternalHandler sHandler = new InternalHandler(); mFuture = new FutureTask<Result>(mWorker) { @Override protected void More ...done() { Message message; Result result = null; try { result = get(); } catch (InterruptedException e) { (LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occured while executing doInBackground()", ()); } catch (CancellationException e) { message = (MESSAGE_POST_CANCEL, new AsyncTaskResult<Result>(, (Result[]) null)); (); return; } catch (Throwable t) { throw new RuntimeException("An error occured while executing " + "doInBackground()", t); } message = (MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(, result)); (); } }; private static class InternalHandler extends Handler { @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void More ...handleMessage(Message msg) { AsyncTaskResult result = (AsyncTaskResult) ; switch () { case MESSAGE_POST_RESULT: // There is only one result ([0]); break; case MESSAGE_POST_PROGRESS: (); break; case MESSAGE_POST_CANCEL: (); break; } } }
Let’s look at the code below. The first step is to request a picture and parse the comments.
import ; import ; import ; import ; import ; import ; import ; /** * Network cache * * @author Ace * @date 2016-02-18 */ public class NetCacheUtils { private LocalCacheUtils mLocalUtils; private MemoryCacheUtils mMemoryUtils; public NetCacheUtils(LocalCacheUtils localUtils, MemoryCacheUtils memoryUtils) { mLocalUtils = localUtils; mMemoryUtils = memoryUtils; } public void getBitmapFromNet(ImageView imageView, String url) { BitmapTask task = new BitmapTask(); (imageView, url); } /** * AsyncTask is the thread pool + handler encapsulation. The first generic is: the parameter type type of the parameter (which is consistent with doInBackground). The second generic is: * The parameter type of the update progress (consistent with onProgressUpdate) The third generic: the parameter type of the return result (consistent with onPostExecute, * The return type is the same as doInBackground) */ class BitmapTask extends AsyncTask<Object, Integer, Bitmap> { private ImageView mImageView; private String url; // The main thread is running, preloaded@Override protected void onPreExecute() { (); } // The child thread runs, the asynchronous loading logic is processed in this method@Override protected Bitmap doInBackground(Object... params) { mImageView = (ImageView) params[0]; url = (String) params[1]; (url);//Bind imageView and url together// publishProgress(values)// Notify progress// Download the picturereturn download(url); } // The main thread is running, update progress@Override protected void onProgressUpdate(Integer... values) { (values); } // The main thread is running, update the main interface@Override protected void onPostExecute(Bitmap result) { if (result != null) { // Determine whether the current image is the image you want from the imageView to prevent the image disorder caused by listview reuseString bindUrl = (String) (); if ((url)) { // Set image for imageView(result); // Save the image locally(result, url); // Save the image in memory(url, result); } } } } /** * Download the picture * * @param url */ public Bitmap download(String url) { HttpURLConnection conn = null; try { conn = (HttpURLConnection) (new URL(url).openConnection()); (5000); (5000); ("GET"); (); int responseCode = (); if (responseCode == 200) { InputStream in = (); // Convert streams into bitmap objectsBitmap bitmap = (in); return bitmap; } } catch (Exception e) { (); } finally { if (conn != null) { (); } } return null; } }
It's very simple to use LruCache. I simply translate the following document:
* A cache that holds strong references to a limited number of values. Each time * a value is accessed, it is moved to the head of a queue. When a value is * added to a full cache, the value at the end of that queue is evicted and may * become eligible for garbage collection. * CacheSave a strong quote to limit the amount of content,wheneverItemWhen visited,thisItemIt will move to the head of the queue。 * whencacheAdd new ones when they are fullitemhour,At the end of the queueitemWill be recycled。 * <p>If your cached values hold resources that need to be explicitly released, * override {@link #entryRemoved}. * if youcacheA certain value of need to be explicitly released,RewriteentryRemoved() * <p>By default, the cache size is measured in the number of entries. Override * {@link #sizeOf} to size the cache in different units. For example, this cache * is limited to 4MiB of bitmaps: defaultcacheSize is measureditemNumber of,RewritesizeofCalculate differentlyitemof * size。 {@code * int cacheSize = 4 * 1024 * 1024; // 4MiB * LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { * protected int sizeOf(String key, Bitmap value) { * return (); * } * }} ------------------------------------------------------------------- <p>This class is thread-safe. Perform multiple cache operations atomically by * synchronizing on the cache: <pre> {@code * synchronized (cache) { * if ((key) == null) { * (key, value); * } * }}</pre> * 他是线程安全of,Automatically perform multiple cache operations and lock them ------------------------- <p>This class does not allow null to be used as a key or value. A return * value of null from {@link #get}, {@link #put} or {@link #remove} is * unambiguous: the key was not in the cache. * Not allowedkeyorvaluefornull * whenget(),put(),remove()返回值fornullhour,key相应of项不在cachemiddle
The most important thing is probably the above points: It is very simple to use and look at the code.
import ; import .; /** * Memory cache tool class * * @author Ace * @date 2016-02-19 */ public class MemoryCacheUtils { // Android 2.3 (API Level // 9) Starting, the garbage collector will be more inclined to recycle objects holding soft or weak references, which makes soft and weak references no longer reliable. It is recommended to use LruCache, which is a strong referenceprivate LruCache<String, Bitmap> mCache; public MemoryCacheUtils() { int maxMemory = (int) ().maxMemory();// Get the maximum memory allocated by the virtual machine// 16M // LRU is used at least recently, and the memory overflow is solved by controlling the memory to not exceed the maximum value (specified by the developer). As translated above, if the cache is full, it will clean up the cache object that is least recently used.mCache = new LruCache<String, Bitmap>(maxMemory / 8) { @Override protected int sizeOf(String key, Bitmap value) { // Calculate the size of a bitmapint size = () * ();// The number of bytes in each line is multiplied by heightreturn size; } }; } public Bitmap getBitmapFromMemory(String url) { return (url); } public void setBitmapToMemory(String url, Bitmap bitmap) { (url, bitmap); } }
Last level cache Local cache Save the image downloaded from the network in the form of MD5 to the memory card's formulation directory
/** * Local cache tool class * * @author Ace * @date 2016-02-19 */ public class LocalCacheUtils { // Image cache folderpublic static final String DIR_PATH = Environment .getExternalStorageDirectory().getAbsolutePath() + "/ace_bitmap_cache"; public Bitmap getBitmapFromLocal(String url) { try { File file = new File(DIR_PATH, (url)); if (()) { Bitmap bitmap = (new FileInputStream( file)); return bitmap; } } catch (Exception e) { (); } return null; } public void setBitmapToLocal(Bitmap bitmap, String url) { File dirFile = new File(DIR_PATH); // Create folder. The folder does not exist or it is not a folder. Create a folder. The difference between mkdirs and mkdir is that if the folder has several layers of paths, the former will create the missing parent directory. The latter will not create these parent directories.if (!() || !()) { (); } try { File file = new File(DIR_PATH, (url)); // Save the image compression locally, see 1: Compression format; see 2: Compression quality (0-100); see 3: Output stream(, 100, new FileOutputStream(file)); } catch (Exception e) { (); } } }
MD5Encoder
import ; public class MD5Encoder { public static String encode(String string) throws Exception { byte[] hash = ("MD5").digest(("UTF-8")); StringBuilder hex = new StringBuilder( * 2); for (byte b : hash) { if ((b & 0xFF) < 0x10) { ("0"); } ((b & 0xFF)); } return (); } }
Finally, create a new tool class to use our three cache tool classes above
/** * Level 3 cache tool class * * @author Ace * @date 2016-02-19 */ public class MyBitmapUtils { // Network caching tool classprivate NetCacheUtils mNetUtils; // Local cache tool classprivate LocalCacheUtils mLocalUtils; // Memory cache tool classprivate MemoryCacheUtils mMemoryUtils; public MyBitmapUtils() { mMemoryUtils = new MemoryCacheUtils(); mLocalUtils = new LocalCacheUtils(); mNetUtils = new NetCacheUtils(mLocalUtils, mMemoryUtils); } public void display(ImageView imageView, String url) { // Set default loading of pictures(.news_pic_default); // Load from memory cache firstBitmap bitmap = (url); if (bitmap != null) { (bitmap); ("Reading pictures from memory..."); return; } // Load from local cachebitmap = (url); if (bitmap != null) { (bitmap); ("Read pictures from local..."); // Set pictures for memory(url, bitmap); return; } // Load from network cache(imageView, url); } }
The above mentioned introduces you the relevant knowledge of Android asynchronous request images plus level 3 cache, and I hope it will be helpful to you.