当前位置:网站首页>Android implements the caching mechanism and caches multiple data types
Android implements the caching mechanism and caches multiple data types
2022-07-26 09:22:00 【LHBTM】
http://blog.csdn.net/zhoubin1992/article/details/46379055
Finally, attach the full code link of the tool class
ASimpleCache Framework source code link
https://github.com/yangfuhai/ASimpleCache
Yang Shen's works , Everyone should be most familiar with him afinal Frame bar
The official introduction
ASimpleCache One is for android To formulate the Lightweight Open source caching framework . Lightweight to just one java file ( It comes from a dozen classes ).
1、 It can cache something ?
Normal string 、JsonObject、JsonArray、Bitmap、Drawable、 Serialized java object , and byte data .
2、 What are its characteristics ?
The main features are :
1: light , It's as light as one JAVA file .
2: Configurable , You can configure the cache path , Cache size , Number of caches, etc .
3: You can set Cache timeout , Cache timeout is automatically invalidated , And deleted .
4: Support multiple processes .
3、 It's in android What scenarios can be used in ?
1、 Replace SharePreference As a configuration file
2、 Sure Cache network request data , such as oschina Of android The client can cache http Requested news content , The cache time is assumed to be 1 Hours , It will automatically expire after timeout , Let the client request new data again , Reduce client traffic , At the same time, reduce server concurrency .
3、 For you …
4、 How to use ASimpleCache?
Here is a small demo, I hope you like :
ACache mCache = ACache.get(this);
mCache.put("test_key1", "test value");
mCache.put("test_key2", "test value", 10);// preservation 10 second , If exceeded 10 Seconds to get this key, Will be for null
mCache.put("test_key3", "test value", 2 * ACache.TIME_DAY);// Keep it for two days , If it takes more than two days to get this key, Will be for null
get data
ACache mCache = ACache.get(this);
String value = mCache.getAsString("test_key1");
Source code analysis
One 、ACache Class structure diagram
ASimpleCache There's only one JAVA file ——ACache.java
First of all, I used mind mapping to make ACache Detailed structure diagram of class :
Two 、 official demo analysis
By analyzing the official demo To drive source code analysis
Take string storage as an example ( It's official demo There are many examples of data reading in , In fact, the method is similar ), open SaveStringActivity.java:
package com.yangfuhai.asimplecachedemo;
import org.afinal.simplecache.ACache;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
/** * * @ClassName: SaveStringActivity * @Description: cache string * @Author Yoson Hao * @WebSite www.haoyuexing.cn * @Email [email protected] * @Date 2013-8-7 Afternoon 9:59:43 * */
public class SaveStringActivity extends Activity {
private EditText mEt_string_input;
private TextView mTv_string_res;
private ACache mCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_save_string);
// Initialize control
initView();
mCache = ACache.get(this);
}
/** * Initialize control */
private void initView() {
mEt_string_input = (EditText) findViewById(R.id.et_string_input);
mTv_string_res = (TextView) findViewById(R.id.tv_string_res);
}
/** * Click on save event * * @param v */
public void save(View v) {
if (mEt_string_input.getText().toString().trim().length() == 0) {
Toast.makeText(
this,
"Cuz u input is a nullcharacter ... So , when u press \"read\" , if do not show any result , plz don't be surprise",
Toast.LENGTH_SHORT).show();
}
// mCache.put("testString", mEt_string_input.getText().toString());
mCache.put("testString", mEt_string_input.getText().toString(),300);
}
/** * Click on read event * * @param v */
public void read(View v) {
String testString = mCache.getAsString("testString");
if (testString == null) {
Toast.makeText(this, "String cache is null ...", Toast.LENGTH_SHORT)
.show();
mTv_string_res.setText(null);
return;
}
mTv_string_res.setText(testString);
}
/** * Click on clear event * * @param v */
public void clear(View v) {
mCache.remove("testString");
}
}
You can see that the method of reading the cache string is very simple !!!
- stay onCreate Pass through get Get the cache instance
mCache = ACache.get(this); - stay save Button click event , adopt put Method to save the string to the cache instance
mCache.put(“testString”, mEt_string_input.getText().toString(),300); - stay read Button click event , adopt getAsString Method to read the string from the cache instance
mCache.getAsString(“testString”);
Other data reading , The method is similar , These are also the three steps .300 For save time 300 second .
3、 ... and 、ACache Source code analysis
1、 Get cache instance
Then we went from ACache.get() Let's get started , Actually, check the mind map above ,ACache The construction method of class is private Of , So the new cache instance can only be created through ACache.get How to get .
// Instantiate the application scenario cache
public static ACache get(Context ctx) {
return get(ctx, "ACache");
}
// Create a new cache directory
public static ACache get(Context ctx, String cacheName) {
// New folder , The file path is the application scenario cache path directory , The folder name is ACache(new File() You can also create a new file , Just add the suffix )
File f = new File(ctx.getCacheDir(), cacheName);
return get(f, MAX_SIZE, MAX_COUNT);
}
// Create a new cache instance , Save the instance map,key Cache directory + Each application starts the process id
public static ACache get(File cacheDir, long max_zise, int max_count) {
// return key Cache directory + Each application starts the process id Of map Of value value , Assign to cache instance manager
ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid());
if (manager == null) { // When the cache instance is empty ,
manager = new ACache(cacheDir, max_zise, max_count);
mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager);// Insert map
}
return manager;
}
Calling ACache.get(Context) In the process of method , Actually, three get Method
(1)get(Context ctx)->(2)get(Context ctx, String cacheName)->(3)get(File cacheDir, long max_zise, int max_count)
stay (2) A new cache directory is created in , Path is :
/data/data/app-package-name/cache/ACache
Cache size MAX_SIZE And quantity MAX_COUNT All by final Variable control .
In fact, the final call (3) Get instance :
mInstanceMap Of key Cache directory + Each application starts the process id,value by ACache.
Initial operation ,mInstanceMap There are no key value pairs , therefore manager == null. So through ACache Construction method constructs a new instance , Finally, the instance reference is saved in mInstanceMap.
So let's see ACache Construction method :
//ACache Constructors by private private ( So you can only get instances in other classes through get() Method )
private ACache(File cacheDir, long max_size, int max_count) {
if (!cacheDir.exists() && !cacheDir.mkdirs()) { // When the cache directory does not exist and cannot be created , Throw an exception
throw new RuntimeException("can't make dirs in " + cacheDir.getAbsolutePath());
}
mCache = new ACacheManager(cacheDir, max_size, max_count);// Instantiation ACacheManager Inner class instance
}
When the cache directory does not exist and cannot be created , Throw an exception , Otherwise instantiate ACacheManager Inner class instance ( Cache manager ).ACacheManager The constructor of the inner class is as follows :
// Inner class ACacheManager Constructor for
private ACacheManager(File cacheDir, long sizeLimit, int countLimit) {
this.cacheDir = cacheDir;
this.sizeLimit = sizeLimit;
this.countLimit = countLimit;
cacheSize = new AtomicLong(); // Atomic class instances cacheSize, Do not lock to ensure thread safety
cacheCount = new AtomicInteger(); // Atomic class instances cacheCount, Do not lock to ensure thread safety
calculateCacheSizeAndCacheCount();
}
Constructor gets the atomic class instance cacheSize and cacheCount, adopt calculateCacheSizeAndCacheCount(); Method to calculate cacheSize and cacheCount as follows :
/** * Calculation cacheSize and cacheCount */
private void calculateCacheSizeAndCacheCount() {
new Thread(new Runnable() {
@Override
public void run() {
//int size = 0;
long size = 0; // here long The type is right ——by Herding
int count = 0;
File[] cachedFiles = cacheDir.listFiles(); // Return to the cache directory cacheDir File array under
if (cachedFiles != null) {
for (File cachedFile : cachedFiles) { // Traverse the file array
size += calculateSize(cachedFile);
count += 1;
lastUsageDates.put(cachedFile, cachedFile.lastModified()); // Insert the cache file and the last modification time map
}
cacheSize.set(size); // Set to the given value
cacheCount.set(count); // Set to the given value
}
}
}).start();
}
calculateCacheSizeAndCacheCount Method to calculate the size and number of threads . After calculation, deposit cacheSize and cacheCount,cacheSize and cacheCount Defined in the inner class as AtomicLong and AtomicInteger Quantum class , That is, thread safe . Its basic characteristic is in multithreading environment , When there are multiple threads executing the methods contained in the instances of these classes at the same time , Be exclusive , That is, when a thread enters a method , When executing the instructions , Will not be interrupted by other threads , And other threads are like spinlocks , Wait until the method execution is complete , Only by JVM Select another thread from the waiting queue to enter .
Get the cache instance here , Mainly completed the following work :
- New cache directory
- adopt ACache Construction method constructs a new instance , And insert the instance reference mInstanceMap
- Instantiation ACacheManager, Calculation cacheSize and cacheCount
Next is data access operations .
2、 Store data into the cache instance
From the mind map above public method( Reading and writing methods of various data ) in , Yes Various public Of put and get And other methods to cache data of various data types . By the above demo Of put Method
mCache.put(“testString”, mEt_string_input.getText().toString(),300); We found the prototype :
/** * preservation String data To In cache * * @param key * The saved key * @param value * The saved String data * @param saveTime * Time of preservation , Company : second */
public void put(String key, String value, int saveTime) {
put(key, Utils.newStringWithDateInfo(saveTime, value));
}
there put Method can specify the cache time . Call another of his own put Method :
/** * preservation String data To In cache * * @param key * The saved key * @param value * The saved String data */
public void put(String key, String value) {
File file = mCache.newFile(key); // New file
BufferedWriter out = null; // Buffer character output stream , The function is to add some buffer function for other character output streams
try {
out = new BufferedWriter(new FileWriter(file), 1024); // obtain file Character stream
out.write(value); // hold value write in
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
mCache.put(file); // to update cacheCount and cacheSize lastUsageDates Insert the key value pair of the new file and time
}
}
stay put(String key, String value) Method first calls mCache.newFile(key) Create a new file :
// New file
private File newFile(String key) {
return new File(cacheDir, key.hashCode() + ""); // New file , The file named key Integer hash code of
}
New The file named key Integer hash code of . go back to put(String key, String value) in , And then through out.write(value); Store data in a file . Last call mCache.put(file); Conduct ACacheManager Update the instance :
// to update cacheCount and cacheSize lastUsageDates Insert the key value pair of the new file and time
// After the file is put into the program cache , Count the total cache , total , Files are stored in files map in (value The value is the last modification time of the file , It is convenient to destroy according to the set destruction time )
// The cache does not exceed the limit , Then increase the total cache , The value of the total
// The cache exceeds the limit , Reduce the total cache , The value of the total
// adopt removeNext Method to find the size of the oldest file
private void put(File file) {
int curCacheCount = cacheCount.get(); // Get quantity
while (curCacheCount + 1 > countLimit) { // Greater than upper limit
long freedSize = removeNext(); // Remove old files , Return file size
cacheSize.addAndGet(-freedSize); // to update cacheSize
curCacheCount = cacheCount.addAndGet(-1);// to update cacheCount
}
cacheCount.addAndGet(1);// to update cacheCount
long valueSize = calculateSize(file); // Calculate file size
long curCacheSize = cacheSize.get(); // Gets the current cache size
while (curCacheSize + valueSize > sizeLimit) { // Greater than upper limit
long freedSize = removeNext(); // Remove old files , Return file size
curCacheSize = cacheSize.addAndGet(-freedSize); // to update curCacheSize
}
cacheSize.addAndGet(valueSize); // to update cacheSize
Long currentTime = System.currentTimeMillis();
file.setLastModified(currentTime); // Set the last modification time of the file
lastUsageDates.put(file, currentTime); // Insert map
}
Analysis finished ACacheManager Of put() after , We go back to put(key, Utils.newStringWithDateInfo(saveTime, value))
The second parameter value What's coming in is Utils.newStringWithDateInfo(saveTime, value), and newStringWithDateInfo yes ACache A method of the internal tool class of , stay value Time information is added in front of the content :
// Return time information +value
private static String newStringWithDateInfo(int second, String strInfo) {
return createDateInfo(second) + strInfo;
}
Back to stitching createDateInfo(second) and value String .createDateInfo() as follows :
// Time information
private static String createDateInfo(int second) {
String currentTime = System.currentTimeMillis() + "";
while (currentTime.length() < 13) { // Less than 13, Front complement 0
currentTime = "0" + currentTime;
}
return currentTime + "-" + second + mSeparator; // current time - Storage time
}
The return string format is current time - Storage time “ ”
3、 Read data from the cache instance
By the above demo Of get Method mCache.getAsString(“testString”); We found the prototype :
/** * Read String data * * @param key * @return String data */
public String getAsString(String key) {
File file = mCache.get(key); // get files
if (!file.exists())
return null;
boolean removeFile = false;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
String readString = "";
String currentLine;
while ((currentLine = in.readLine()) != null) { // Traverse line by line
readString += currentLine; // Each line of string is connected
}
if (!Utils.isDue(readString)) { //String Data has not expired
return Utils.clearDateInfo(readString);// Remove the string content of time information
} else {
removeFile = true; // Remove the file flag bit to true
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (removeFile)
remove(key); // Remove the cache
}
}
getAsString(String key) In the method, first of all through Cache manager mCache.get(key) Method to get the file , And then use Utils.isDue(readString)** Determine whether the string data expires , Unexpired returns the string content of the time information removed ; Remove the cache when it expires , Returns an empty .**Utils.isDue(readString) Called isDue(byte[] data) Judge :
/** * Determine the cache size byte Whether the data is due * * @param data * @return true: It's due false: It hasn't expired yet */
private static boolean isDue(byte[] data) {
String[] strs = getDateInfoFromDate(data);
if (strs != null && strs.length == 2) {
String saveTimeStr = strs[0];
while (saveTimeStr.startsWith("0")) {
saveTimeStr = saveTimeStr.substring(1, saveTimeStr.length());
}
long saveTime = Long.valueOf(saveTimeStr);
long deleteAfter = Long.valueOf(strs[1]);
if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) {
return true;
}
}
return false;
}
So far, the whole cache string reading process is ACache The source code analysis of is completed , The analysis process of other cache data type reading methods is the same .
JsonObject、JsonArray、Bitmap、Drawable、 Serialized data stored in the cache is converted into strings /byte Format , Call function again put(String key, String value) that will do .
such as BitMap The preservation of the :
/** * preservation bitmap To In cache , There is time to save * * @param key * The saved key * @param value * The saved bitmap data * @param saveTime * Time of preservation , Company : second */
public void put(String key, Bitmap value, int saveTime) {
put(key, Utils.Bitmap2Bytes(value), saveTime);
}
Bitmap The read :
/** * Read bitmap data * * @param key * @return bitmap data */
public Bitmap getAsBitmap(String key) {
if (getAsBinary(key) == null) {
return null;
}
return Utils.Bytes2Bimap(getAsBinary(key));
}
Thought is to put bitmap Turn into byte[], Then call cache byte Function of . adopt Utils.Bitmap2Bytes(value) complete Bitmap → byte[] Transformation . adopt Utils.Bytes2Bimap(getAsBinary(key)) complete byte[] → Bitmap Transformation .
/* * Bitmap → byte[] */
private static byte[] Bitmap2Bytes(Bitmap bm) {
if (bm == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();//byte[] Output stream
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);// According to the specified image format and quality , Converting pictures to output streams . The compressed image , No compression is 100, Indicates that the compression ratio is 0
return baos.toByteArray();
}
/* * byte[] → Bitmap */
private static Bitmap Bytes2Bimap(byte[] b) {
if (b.length == 0) {
return null;
}
return BitmapFactory.decodeByteArray(b, 0, b.length);// analysis
}
Very simple. .Drawable The cache of is first converted to Bitmap, Then the above steps are converted into byte.
summary
The open source library class is simple , Easy to understand .
- have access to ACache Cache data that does not need real-time updates , One is to reduce network requests , Secondly, the local loading speed is also fast .
- You can set the cache time .
- Can replace SharePreference As a configuration file , Save multiple data types , For example, you can save avatar information .
边栏推荐
- 使用openLayer画箭头
- Bloom filter
- Does volatile rely on the MESI protocol to solve the visibility problem? (next)
- 大二上第五周学习笔记
- Cat installation and use
- MySQL 强化知识点
- [shutter -- layout] detailed explanation of the use of align, center and padding
- OFDM 十六讲- OFDM
- Zipkin installation and use
- Under a directory of ext3 file system, subfolders cannot be created, but files can be created
猜你喜欢
Stm32+mfrc522 completes IC card number reading, password modification, data reading and writing
【Mysql】Mysql锁详解(三)
el-table实现增加/删除行,某参数跟着变
原根与NTT 五千字详解
Server memory failure prediction can actually do this!
Basic use of ArcGIS 1
[MySQL] how to execute an SQL statement (2)
神经网络与深度学习-6- 支持向量机1 -PyTorch
MySQL transaction
2022 tea artist (intermediate) special operation certificate examination question bank simulated examination platform operation
随机推荐
Apple generated and verified tokens for PHP
解决“NOTE: One or more layouts are missing the layout_width or layout_height attributes.”
What is asynchronous operation
el-table的formatter属性的用法
大二上第二周学习笔记
【线上死锁分析】由index_merge引发的死锁事件
arcgis的基本使用4
Li Mu D2L (VI) -- model selection
760. 字符串长度
暑假末尾学习笔记
C# Serialport的发送和接收
antUI中a-modal 拖拽功能制作
Advanced mathematics | Takeshi's "classic series" daily question train of thought and summary of error prone points
When you click input, the border is not displayed!
PHP 之 Apple生成和验证令牌
HBuilderX 运行微信开发者工具 “Fail to open IDE“报错解决
原根与NTT 五千字详解
839. 模拟堆
暑假第四周
The problem of the sum of leetcode three numbers