├── cachemanager
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── lujianchao
│ │ │ │ └── cachemanager
│ │ │ │ ├── BasicApp.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── CacheManager.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── lujianchao
│ │ │ └── cachemanager
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── lujianchao
│ │ └── cachemanager
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── .gitattributes
├── .gitignore
└── README.md
/cachemanager/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/cachemanager/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CacheManager
3 |
4 |
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/AndroidCacheManager/HEAD/cachemanager/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/cachemanager/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/cachemanager/src/main/java/com/lujianchao/cachemanager/BasicApp.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.cachemanager;
2 |
3 | import android.app.Application;
4 |
5 | /**
6 | * Created by hnvfh on 2017/3/14.
7 | */
8 |
9 | public class BasicApp extends Application {
10 |
11 | @Override
12 | public void onCreate () {
13 | super.onCreate ();
14 | CacheManager.init (this);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/cachemanager/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/cachemanager/src/test/java/com/lujianchao/cachemanager/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.cachemanager;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect () throws Exception {
15 | assertEquals (4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/cachemanager/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/cachemanager/src/main/java/com/lujianchao/cachemanager/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.cachemanager;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Toast;
7 |
8 | public class MainActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate (Bundle savedInstanceState) {
12 | super.onCreate (savedInstanceState);
13 | setContentView (R.layout.activity_main);
14 | CacheManager.updateCache (CacheManager.HistoryCache.BannerList,"{\"name\":\"张三\",\"age\":34}");
15 | }
16 | public void test(View mView){
17 | CacheManager.updateCache (CacheManager.HistoryCache.BannerList,"{\"name\":\"张三\",\"age\":34}");
18 | Toast.makeText (this,CacheManager.getCache (CacheManager.HistoryCache.BannerList).getValue (),Toast.LENGTH_LONG).show ();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/cachemanager/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/cachemanager/src/androidTest/java/com/lujianchao/cachemanager/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.cachemanager;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith (AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext () throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext ();
23 |
24 | assertEquals ("com.lujianchao.cachemanager", appContext.getPackageName ());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cachemanager/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/cachemanager/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.lujianchao.cachemanager"
9 | minSdkVersion 19
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | debug {
23 | resValue("string", "PORT_NUMBER", "8081")
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | compile 'com.android.support:appcompat-v7:25.2.0'
34 | debugCompile 'com.amitshekhar.android:debug-db:1.0.0'
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 |
38 | # Keystore files
39 | *.jks
40 |
41 | # =========================
42 | # Operating System Files
43 | # =========================
44 |
45 | # OSX
46 | # =========================
47 |
48 | .DS_Store
49 | .AppleDouble
50 | .LSOverride
51 |
52 | # Thumbnails
53 | ._*
54 |
55 | # Files that might appear in the root of a volume
56 | .DocumentRevisions-V100
57 | .fseventsd
58 | .Spotlight-V100
59 | .TemporaryItems
60 | .Trashes
61 | .VolumeIcon.icns
62 |
63 | # Directories potentially created on remote AFP share
64 | .AppleDB
65 | .AppleDesktop
66 | Network Trash Folder
67 | Temporary Items
68 | .apdisk
69 |
70 | # Windows
71 | # =========================
72 |
73 | # Windows image file caches
74 | Thumbs.db
75 | ehthumbs.db
76 |
77 | # Folder config file
78 | Desktop.ini
79 |
80 | # Recycle Bin used on file shares
81 | $RECYCLE.BIN/
82 |
83 | # Windows Installer files
84 | *.cab
85 | *.msi
86 | *.msm
87 | *.msp
88 |
89 | # Windows shortcuts
90 | *.lnk
91 |
--------------------------------------------------------------------------------
/cachemanager/src/main/java/com/lujianchao/cachemanager/CacheManager.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.cachemanager;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 |
9 | import java.lang.reflect.Field;
10 | import java.util.ArrayList;
11 | import java.util.Iterator;
12 | import java.util.List;
13 |
14 | /**
15 | * Created by lujianchao on 2016/11/29.
16 | *
17 | * @author lujianchao
18 | */
19 |
20 | public class CacheManager {
21 |
22 |
23 |
24 | public static final String DBName = "appinfo.db";
25 | /**
26 | * 更改类文件必须更改版本号,否则不会更新缓存结构
27 | */
28 | public static final int DBVersion = 1;
29 | private static DBHelper mCacheDBHelper;
30 | private static SQLiteDatabase mSQLiteDatabase;
31 | private static Context mContext;
32 |
33 | public static void init (Context mContext1) {
34 | mContext = mContext1;
35 |
36 | }
37 |
38 | /**
39 | * 删除数据库
40 | */
41 | public synchronized static void deleteDB () {
42 | mContext.deleteDatabase (DBName);
43 | }
44 |
45 | /**
46 | * 更新缓存
47 | *
48 | * @param key 预定义名称
49 | * @param value 待缓存数据
50 | */
51 | public synchronized static void updateCache (String key, String value) {
52 | updateCache (new CacheEntity ().setKey (key).setValue (value));
53 | }
54 |
55 | /**
56 | * 更新缓存
57 | * 不能手动更新id、key和lasttime
58 | *
59 | * @param mCacheEntity
60 | */
61 | public synchronized static void updateCache (CacheEntity mCacheEntity) {
62 | if (mCacheDBHelper == null) {
63 | mCacheDBHelper = new DBHelper (mContext, DBName, null, DBVersion);
64 | }
65 | if (mSQLiteDatabase == null) {
66 | mSQLiteDatabase = mCacheDBHelper.getWritableDatabase ();
67 | }
68 | ContentValues m = new ContentValues ();
69 | m.put ("value", mCacheEntity.value);
70 | m.put ("lasttime", System.currentTimeMillis ());
71 | m.put ("bak", mCacheEntity.bak);
72 | m.put ("flag", mCacheEntity.flag);
73 | try {
74 | mSQLiteDatabase.update (HistoryCache.class.getSimpleName (), m, "key=?", new String[]{mCacheEntity.key});
75 | } catch (Exception mE) {
76 | mE.printStackTrace ();
77 | }
78 | }
79 |
80 | /**
81 | * 获取缓存数据
82 | *
83 | * @param key 预定义名称
84 | * @return 缓存数据,异常或者不存在则返回null
85 | */
86 | public static CacheEntity getCache (String key) {
87 | CacheEntity mCacheEntity = new CacheEntity ();
88 | if (mCacheDBHelper == null) {
89 | mCacheDBHelper = new DBHelper (mContext, DBName, null, DBVersion);
90 | }
91 | if (mSQLiteDatabase == null) {
92 | mSQLiteDatabase = mCacheDBHelper.getWritableDatabase ();
93 | }
94 | Cursor mCursor = null;
95 | try {
96 | mCursor = mSQLiteDatabase.rawQuery ("select * from " + HistoryCache.class.getSimpleName () + " where key=?", new String[]{key});
97 | if (mCursor != null && mCursor.getCount () == 1) {
98 | mCursor.moveToNext ();
99 | mCacheEntity.id = mCursor.getInt (0);
100 | mCacheEntity.key = mCursor.getString (1);
101 | mCacheEntity.value = mCursor.getString (2);
102 | mCacheEntity.lasttime = mCursor.getLong (3);
103 | mCacheEntity.bak = mCursor.getString (4);
104 | mCacheEntity.flag = mCursor.getString (5);
105 |
106 | }
107 | } catch (Exception mE) {
108 | mE.printStackTrace ();
109 | } finally {
110 | if (mCursor != null) {
111 | mCursor.close ();
112 | }
113 | return mCacheEntity;
114 | }
115 | }
116 |
117 | /**
118 | * 数据库表结构
119 | */
120 | public static class CacheEntity {
121 | private String value="";
122 | private String key="";
123 | private int id;
124 | private long lasttime;
125 | private String bak="";
126 | private String flag="";
127 |
128 | public String getValue () {
129 | return value;
130 | }
131 |
132 | public CacheEntity setValue (final String mValue) {
133 | value = mValue;
134 | return this;
135 | }
136 |
137 | public String getKey () {
138 | return key;
139 | }
140 |
141 | public CacheEntity setKey (final String mKey) {
142 | key = mKey;
143 | return this;
144 | }
145 |
146 | public int getId () {
147 | return id;
148 | }
149 |
150 | public CacheEntity setId (final int mId) {
151 | id = mId;
152 | return this;
153 | }
154 |
155 | public long getLasttime () {
156 | return lasttime;
157 | }
158 |
159 | public CacheEntity setLasttime (final long mLasttime) {
160 | lasttime = mLasttime;
161 | return this;
162 | }
163 |
164 | public String getBak () {
165 | return bak;
166 | }
167 |
168 | public CacheEntity setBak (final String mBak) {
169 | bak = mBak;
170 | return this;
171 | }
172 |
173 | public String getFlag () {
174 | return flag;
175 | }
176 |
177 | public CacheEntity setFlag (final String mFlag) {
178 | flag = mFlag;
179 | return this;
180 | }
181 | }
182 |
183 | /**
184 | * Created by lujianchao on 2016/11/29.
185 | * SQLiteOpenHelper
186 | *
187 | * @author lujianchao
188 | */
189 | public static class DBHelper extends SQLiteOpenHelper {
190 | private static final String CREATE_CacheTABLE = "create table historycache (id integer primary key autoincrement, key text, value text, lasttime long, bak text, flag text)";
191 |
192 | public DBHelper (final Context context, final String name, final SQLiteDatabase.CursorFactory factory, final int version) {
193 | super (context, name, factory, version);
194 | }
195 |
196 | @Override
197 | public void onCreate (final SQLiteDatabase db) {
198 | db.execSQL (CREATE_CacheTABLE);
199 | updatetable (db, HistoryCache.class);
200 | }
201 |
202 | @Override
203 | public void onUpgrade (final SQLiteDatabase db, final int oldVersion, final int newVersion) {
204 | updatetable (db, HistoryCache.class);
205 | }
206 |
207 | /**
208 | * 传入的类名即为表名,传入的类的属性即为表内的记录,字段固定,用来实现动态增减记录,记录为缓存内容,所以数量较少,
209 | * 只需要更改实体类属性,就可以管理数据库了,动态升级。
210 | *
211 | * @param db
212 | * @param mClass
213 | */
214 | private void updatetable (final SQLiteDatabase db, Class mClass) {
215 | /**
216 | * 通过反射拿到当前所有cache名
217 | */
218 | List mList = new ArrayList<> ();
219 | Field[] fields = mClass.getDeclaredFields ();
220 | for (Field fd : fields) {
221 | fd.setAccessible (true);
222 | mList.add (fd.getName ());
223 | }
224 |
225 | Cursor mCursor = db.rawQuery ("select * from " + mClass.getSimpleName (), null);
226 | while (mCursor.moveToNext ()) {
227 | boolean ishave = false;
228 | String string = mCursor.getString (1);
229 | Iterator mStringIterator = mList.iterator ();
230 | while (mStringIterator.hasNext ()) {
231 | if (mStringIterator.next ().equals (string)) {
232 | ishave = true;
233 | mStringIterator.remove ();
234 | break;
235 | }
236 | }
237 | /**
238 | * 类里没有这个缓存名就将其删掉
239 | */
240 | if (!ishave) {
241 | db.delete (mClass.getSimpleName (), "key=?", new String[]{string});
242 | }
243 | }
244 | mCursor.close ();
245 | for (int mI = 0; mI < mList.size (); mI++) {
246 | ContentValues values = new ContentValues ();
247 | values.put ("key", mList.get (mI));
248 | values.put ("lasttime", System.currentTimeMillis ());
249 | db.insert (mClass.getSimpleName (), null, values);
250 | }
251 | }
252 | }
253 |
254 | /**
255 | * Created by lujianchao on 2016/11/29.
256 | * 数据结构
257 | * 添加或者删除属性变量值,都必须更改数据库版本号,否则不会修改
258 | *
259 | * @author lujianchao
260 | */
261 |
262 | public static class HistoryCache {
263 | /**
264 | * 首页
265 | */
266 | public static String IndexPage = "IndexPage";
267 | /**
268 | * 朋友圈
269 | */
270 | public static String FriendLife = "FriendLife";
271 | /**
272 | * 首页Banner图片
273 | */
274 | public static String BannerList = "BannerList";
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Android 简单实现缓存机制(反射和数据库)
2 |
3 | #### 现在的app每个页面都有从服务器后台拿的数据,数据基本是以文本形式返回的,大多数是json格式(json是一种文本形式的文本,跟xml一样,赋予了一定意义),很多app的首页或者朋友圈等类似的功能是没必要总向后台请求的,我们可以把每次请求的数据存起来,下次先拿缓存,有新数据了再追加或替换。
4 |
5 | QQ:1264957104
6 |
7 | Web:http://lujianchao.com
8 |
9 | GitHub:https://github.com/hnsugar
10 |
11 | CSDN:http://blog.csdn.net/hnsugar
12 |
13 | ##一.首先大家会问,为什么要用缓存?
14 |
15 | 如果断网了,app页面还有数据,提示断网,是不是显示不单调了,体验会好不少。有的app断网了就是大白板。。。。说句心里话,我看见大白板的app就想卸载了。
16 |
17 | ##二.原理
18 |
19 |
20 | 简述原理:创建一个表,表结构包括key、value和lasttime等,分别存储键值和保存时间,其他的都是备用,系统的SQLiteOpenHelper有onCreat和onUpgrade方法,触发这两个方法后调用检查数据方法,用反射得到HistoryCache.class的所有属性,遍历属性集合查看是否有key为相应属性的数据,有就不管,没有就添加,数据库表里数据多出的数据被删除,这就是用反射根据类属性动态控制表数据了(不敢说表结构)。剩下的就是update数据和取数据了。
21 | ##三.为什么不动态改变表结构?
22 |
23 |
24 | 仔细看下图,表结构是固定的,有多少条数据也是固定的,根据HistoryCache类决定,但是,数据库增删数据快还是更改表结构快?当然是数据啦,每条数据就是一条缓存,而且,同一个缓存只有一个,只能被更新。如果在app运行时可以随意添加key,那。。。。再次拿缓存就麻烦了,数据库会越来越大,我觉得一条数据代表特定意义的缓存是合理的。
25 | 重要的是,结构有多少条是开发时就订好了,缓存哪里的数据是一一对应的,改不了,这样不会出现脏数据。
26 |
27 |
28 | 基于这种想法,缓存只有获取get方法和更新update方法两个。
29 |
30 |
31 | 说明一下:截图内容是用的https://github.com/amitshekhariitbhu/Android-Debug-Database 这个库可以直接访问局域网手机的数据库,调试时很方便的。推荐
32 |
33 | 
34 |
35 | ##四.开始写代码
36 |
37 | ###1.创建HistoryCache类
38 |
39 | /**
40 | * Created by lujianchao on 2016/11/29.
41 | * 数据结构
42 | * 添加或者删除属性变量值,都必须更改数据库版本号,否则不会修改
43 | *
44 | * @author lujianchao
45 | */
46 |
47 | public static class HistoryCache {
48 | /**
49 | * 首页
50 | */
51 | public static String IndexPage = "IndexPage";
52 | /**
53 | * 朋友圈
54 | */
55 | public static String FriendLife = "FriendLife";
56 | /**
57 | * 首页Banner图片
58 | */
59 | public static String BannerList = "BannerList";
60 | }
61 |
62 | ###2.写SQLiteOpenHelper
63 | sql语句
64 |
65 | private static final String CREATE_CacheTABLE = "create table historycache (id integer primary key autoincrement, key text, value text, lasttime long, bak text, flag text)";
66 |
67 | 提示,我定义的是传入的类的名字和表名是同一个,自定义的dbhelper内封装了根据类属性动态改变数据结构的方法,只在数据库升级时执行。
68 | ```
69 | /**
70 | * Created by lujianchao on 2016/11/29.
71 | * SQLiteOpenHelper
72 | *
73 | * @author lujianchao
74 | */
75 | public static class DBHelper extends SQLiteOpenHelper {
76 |
77 | private static final String CREATE_CacheTABLE = "create table historycache (id integer primary key autoincrement, key text, value text, lasttime long, bak text, flag text)";
78 | public DBHelper (final Context context, final String name, final SQLiteDatabase.CursorFactory factory, final int version) {
79 | super (context, name, factory, version);
80 | }
81 |
82 | @Override
83 | public void onCreate (final SQLiteDatabase db) {
84 | db.execSQL (CREATE_CacheTABLE);
85 | updatetable (db, HistoryCache.class);
86 | }
87 |
88 | @Override
89 | public void onUpgrade (final SQLiteDatabase db, final int oldVersion, final int newVersion) {
90 | updatetable (db, HistoryCache.class);
91 | }
92 |
93 | /**
94 | * 传入的类名即为表名,传入的类的属性即为表内的记录,字段固定,用来实现动态增减记录,记录为缓存内容,所以数量较少,
95 | * 只需要更改实体类属性,就可以管理数据库了,动态升级。
96 | *
97 | * @param db
98 | * @param mClass
99 | */
100 | private void updatetable (final SQLiteDatabase db, Class mClass) {
101 | /**
102 | * 通过反射拿到当前所有cache名
103 | */
104 | List mList = new ArrayList<> ();
105 | Field[] fields = mClass.getDeclaredFields ();
106 | for (Field fd : fields) {
107 | fd.setAccessible (true);
108 | mList.add (fd.getName ());
109 | }
110 |
111 | Cursor mCursor = db.rawQuery ("select * from " + mClass.getSimpleName (), null);
112 | while (mCursor.moveToNext ()) {
113 | boolean ishave = false;
114 | String string = mCursor.getString (1);
115 | Iterator mStringIterator = mList.iterator ();
116 | while (mStringIterator.hasNext ()) {
117 | if (mStringIterator.next ().equals (string)) {
118 | ishave = true;
119 | mStringIterator.remove ();
120 | break;
121 | }
122 | }
123 | /**
124 | * 类里没有这个缓存名就将其删掉
125 | */
126 | if (!ishave) {
127 | db.delete (mClass.getSimpleName (), "key=?", new String[]{string});
128 | }
129 | }
130 | mCursor.close ();
131 | for (int mI = 0; mI < mList.size (); mI++) {
132 | ContentValues values = new ContentValues ();
133 | values.put ("key", mList.get (mI));
134 | values.put ("lasttime", System.currentTimeMillis ());
135 | db.insert (mClass.getSimpleName (), null, values);
136 | }
137 | }
138 | }
139 | ```
140 |
141 | ###3.写CacheManager管理类
142 |
143 | 根据之前的分析,我们只需要updateCache和getCache方法,还有就是deleteDatabase。
144 |
145 | **1.写updateCache()方法:**
146 |
147 | 根据需求,需要根据key更新value值,所以方法如下:
148 |
149 | ```
150 | /**
151 | * 更新缓存
152 | *
153 | * @param key 预定义名称
154 | * @param value 待缓存数据
155 | */
156 | public synchronized static void updateCache (String key, String value) {
157 | updateCache (new CacheEntity ().setKey (key).setValue (value));
158 | }
159 | ```
160 | 一直点下去调用方法是不是很好用呢,我的android tips分类里会介绍如何自定义模板。
161 |
162 |
163 | ```
164 | /**
165 | * 更新缓存
166 | * 不能手动更新id、key和lasttime
167 | *
168 | * @param mCacheEntity
169 | */
170 | public synchronized static void updateCache (CacheEntity mCacheEntity) {
171 | if (mCacheDBHelper == null) {
172 | mCacheDBHelper = new DBHelper (mContext, DBName, null, DBVersion);
173 | }
174 | if (mSQLiteDatabase == null) {
175 | mSQLiteDatabase = mCacheDBHelper.getWritableDatabase ();
176 | }
177 | ContentValues m = new ContentValues ();
178 | m.put ("value", mCacheEntity.value);
179 | m.put ("lasttime", System.currentTimeMillis ());
180 | m.put ("bak", mCacheEntity.bak);
181 | m.put ("flag", mCacheEntity.flag);
182 | try {
183 | mSQLiteDatabase.update (HistoryCache.class.getSimpleName (), m, "key=?", new String[]{mCacheEntity.key});
184 | } catch (Exception mE) {
185 | mE.printStackTrace ();
186 | }
187 | }
188 | ```
189 |
190 | 不能手动更新id、key和lasttime,这些是自动的,可以手动设置就出问题了,道理大家都懂的<( ̄︶ ̄)>
191 |
192 | 忘了介绍CacheEntity这个类了,代码如下:
193 |
194 |
195 | ```
196 | public static class CacheEntity {
197 | private String value="";
198 | private String key="";
199 | private int id;
200 | private long lasttime;
201 | private String bak="";
202 | private String flag="";
203 |
204 | public String getValue () {
205 | return value;
206 | }
207 |
208 | public CacheEntity setValue (final String mValue) {
209 | value = mValue;
210 | return this;
211 | }
212 |
213 | public String getKey () {
214 | return key;
215 | }
216 |
217 | public CacheEntity setKey (final String mKey) {
218 | key = mKey;
219 | return this;
220 | }
221 |
222 | public int getId () {
223 | return id;
224 | }
225 |
226 | public CacheEntity setId (final int mId) {
227 | id = mId;
228 | return this;
229 | }
230 |
231 | public long getLasttime () {
232 | return lasttime;
233 | }
234 |
235 | public CacheEntity setLasttime (final long mLasttime) {
236 | lasttime = mLasttime;
237 | return this;
238 | }
239 |
240 | public String getBak () {
241 | return bak;
242 | }
243 |
244 | public CacheEntity setBak (final String mBak) {
245 | bak = mBak;
246 | return this;
247 | }
248 |
249 | public String getFlag () {
250 | return flag;
251 | }
252 |
253 | public CacheEntity setFlag (final String mFlag) {
254 | flag = mFlag;
255 | return this;
256 | }
257 | }
258 | ```
259 | 至此更新方法就写完了。为什么属性要初始化?总不能让数据库存null吧!
260 |
261 | **2.写getCache()方法:**
262 | 直接上代码了:
263 |
264 | ```
265 | /**
266 | * 获取缓存数据
267 | *
268 | * @param key 预定义名称
269 | * @return 缓存数据,异常或者不存在则返回null
270 | */
271 | public static CacheEntity getCache (String key) {
272 | CacheEntity mCacheEntity = new CacheEntity ();
273 | if (mCacheDBHelper == null) {
274 | mCacheDBHelper = new DBHelper (mContext, DBName, null, DBVersion);
275 | }
276 | if (mSQLiteDatabase == null) {
277 | mSQLiteDatabase = mCacheDBHelper.getWritableDatabase ();
278 | }
279 | Cursor mCursor = null;
280 | try {
281 | mCursor = mSQLiteDatabase.rawQuery ("select * from " + HistoryCache.class.getSimpleName () + " where key=?", new String[]{key});
282 | if (mCursor != null && mCursor.getCount () == 1) {
283 | mCursor.moveToNext ();
284 | mCacheEntity.id = mCursor.getInt (0);
285 | mCacheEntity.key = mCursor.getString (1);
286 | mCacheEntity.value = mCursor.getString (2);
287 | mCacheEntity.lasttime = mCursor.getLong (3);
288 | mCacheEntity.bak = mCursor.getString (4);
289 | mCacheEntity.flag = mCursor.getString (5);
290 |
291 | }
292 | } catch (Exception mE) {
293 | mE.printStackTrace ();
294 | } finally {
295 | if (mCursor != null) {
296 | mCursor.close ();
297 | }
298 | return mCacheEntity;
299 | }
300 | }
301 | ```
302 | #####**3.删除数据库**
303 |
304 | /**
305 | * 删除数据库
306 | */
307 | public synchronized static void deleteDB () {
308 | mContext.deleteDatabase (DBName);
309 | }
310 |
311 | ###五.调用总结
312 |
313 | public void test(View mView){
314 | CacheManager.updateCache (CacheManager.HistoryCache.BannerList,"{\"name\":\"张三\",\"age\":34}");
315 | Toast.makeText (this,CacheManager.getCache (CacheManager.HistoryCache.BannerList).getValue (),Toast.LENGTH_LONG).show ();
316 | }
317 |
318 | OK,测试成功,不截图了,还有就是动态更新表数据结构如图。ok,更改成功,至于$change和serialVersionUID是Object类的,我就不过滤对的那么仔细了,无伤大雅︿( ̄︶ ̄)︿。
319 | 
320 | 
321 | ####**小尾巴**
322 | 个人在倒腾自己的网站:http://lujianchao.com 风格或者数据什么的偶尔出问题,那是我在调试。。。。
323 | GitHub:https://github.com/hnsugar
324 | CSDN:http://blog.csdn.net/hnsugar
325 | 项目地址:我自己的Git服务器 http://lujianchao.com:8081/gitblit/summary/AndroidTips!AndroidCacheManager.git
326 |
--------------------------------------------------------------------------------