├── .gitignore ├── .idea ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── duke │ │ └── dsqlitecache │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── duke │ │ │ └── dsqlitecache │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.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 │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── duke │ └── dsqlitecache │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── duke │ │ └── lib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── duke │ │ │ └── lib │ │ │ ├── DCache.java │ │ │ ├── DContentProvider.java │ │ │ ├── DSQLiteOpenHelper.java │ │ │ └── DUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── duke │ └── lib │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSQLiteCache 2 | ASimpleCache是一个优秀的缓存框架。
3 | 1、可以缓存各类数据,比喻:字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。
4 | 2、轻,轻到只有一个JAVA文件。
5 | 3、可配置,可以配置缓存路径,缓存大小,缓存数量等。
6 | 4、可以设置缓存超时时间,缓存超时自动失效,并被删除。
7 | 5、支持多进程。
8 | 等等
9 | 10 | 怎么使用呢?
11 | ACache.get(MainActivity.this).put("username_key", "admin");
12 | //保存10秒,如果超过10秒去获取这个key,将为null
13 | ACache.get(MainActivity.this).put("password_key", "123456789", 10);
14 | //保存两天,如果超过两天去获取这个key,将为null
15 | ACache.get(MainActivity.this).put("password_key", "123456789", 2 * ACache.TIME_DAY);
16 | 17 | 简单解析此原理:
18 | 项目源码一个类ACache,其实是多个类压缩而来,其内部有多个内部类。因不需要对外公开。
19 | 20 | 初始化:
21 | 当初次调用ACache.get(MainActivity.this)方法时,
22 | 其内部会调用File f = new File(ctx.getCacheDir(), "ACache"),代码,获取缓存目录,当然你也可以指定缓存目录位置。
23 | 然后创建一个此目录的管理工具类,并启动线程扫描此目录下的所有文件,并把文件对象与最后修改时间作为键值对保存在内存的HashMap中。
24 | 25 | put:
26 | 当调用ACache对象的put方法时,以key字符串的hashCode值作为文件名,以value参数的字节数组值作为内容写入文件中。
27 | 如果设置了保存时间,则把当前毫秒数+保存时间的毫秒数+"- "保存到文件内容的开头处。
28 | 29 | get:
30 | 当需要获取值时,首先获取key的hashCode值作为文件名所对应的File对象,然后读取内容。
31 | 先获取前面的时间数据,看是否有或者是否过期,以决定是否需要返回数据到上层。
32 | 在获取文件的正式内容,再转换成字符串或者对象等类型,返回到上层。
33 | 34 | 35 | ASimpleCache框架的以上分析,大概是这样。
36 | 37 | 文本重点是介绍我的DSQLiteCache框架。
38 | 其实呢,就是在上述巨作的基础上修改而来的,项目名称为DSQLiteCache,原谅我用了字母D。
39 | 40 | DSQLiteCache项目技术原理:
41 | 上述大神开发的ACache项目中,是把缓存文件全部获取到,然后保存在内存的HashMap中。个人感觉会占用大量app内存,
42 | 上述大神开发的ACache项目中,使用了大量的同步代码,以及新开线程扫描数据。个人感觉在多线程情况下可能会有问题。
43 | 44 | 故,我的缓存数据都是以二进制的形式保存到SQLite数据库中了,避免占用大量内存。
45 | 我使用了ContentProvider作为数据访问媒介,以避免多线程并发问题。
46 | 我没有把所有的代码压到一个类中。对外暴露的用户接口类为DCache.java,以区分ACache.java。
47 | 因为使用了ContentProvider,所以在获取接口实例时不需要传入上下文了。
48 | 49 | 继承时注意:
50 | 1、使用aar包或者引入源码,都可以。注意一点,如果引入源码的话,注意同时引入AndroidManifest.xml中provider注册代码。
51 | 如果android:authorities=""值变化了,需同时修改DCache.java中的authorities常量值。
52 | 53 | 使用方法:
54 | DCache.get().put(String key, JSONObject o);
55 | DCache.get().put(String key, JSONObject o, long saveTime);
56 | 57 | DCache.get().put(String key, byte[] data);
58 | DCache.get().put(String key, byte[] data, long saveTime);
59 | 60 | DCache.get().put(String key, String data);
61 | DCache.get().put(String key, String data, long saveTime);
62 | 63 | 简单吧,不多说。
64 | 65 | 保存的数据 支持的类型跟ACache一样,字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。
66 | DCache对外暴露的用户接口直接借鉴ACache的了。
67 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.duke.dsqlitecache" 7 | minSdkVersion 15 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'com.android.support:appcompat-v7:26.1.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | implementation project(':lib') 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/duke/dsqlitecache/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.duke.dsqlitecache; 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 | * Instrumented 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.duke.dsqlitecache", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/duke/dsqlitecache/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.duke.dsqlitecache; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.TextView; 8 | 9 | import com.duke.lib.DCache; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | private TextView textView; 13 | private Button button; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_main); 19 | textView = findViewById(R.id.textView); 20 | button = findViewById(R.id.button); 21 | button.setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | String str = DCache.get().getAsString("a"); 25 | if (str == null) { 26 | str = "无数据"; 27 | } 28 | textView.setText(str); 29 | } 30 | }); 31 | DCache.get().put("a", "测试数据", 10000); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 |