├── .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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DSQLiteCache
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/duke/dsqlitecache/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.dsqlitecache;
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 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mengzhinan/DSQLiteCache/77a2125543b34c96ad33ad1c7232fc55e7e0649a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Feb 09 14:36:49 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 |
30 | implementation 'com.android.support:appcompat-v7:26.1.0'
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
34 | }
35 |
--------------------------------------------------------------------------------
/lib/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 |
--------------------------------------------------------------------------------
/lib/src/androidTest/java/com/duke/lib/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
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.lib.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/duke/lib/DCache.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.graphics.Bitmap;
8 | import android.graphics.drawable.Drawable;
9 | import android.net.Uri;
10 |
11 | import org.json.JSONArray;
12 | import org.json.JSONException;
13 | import org.json.JSONObject;
14 |
15 | import java.io.ByteArrayInputStream;
16 | import java.io.ByteArrayOutputStream;
17 | import java.io.IOException;
18 | import java.io.ObjectInputStream;
19 | import java.io.ObjectOutputStream;
20 | import java.io.Serializable;
21 | import java.util.ArrayList;
22 |
23 | /**
24 | * @author: duke
25 | * @datetime: 2018-02-09 17:39
26 | * @deacription:
27 | */
28 | public class DCache {
29 |
30 | public static final int TIME_MINUTE = 60;
31 | public static final int TIME_HOUR = TIME_MINUTE * 60;
32 | public static final int TIME_DAY = TIME_HOUR * 24;
33 |
34 | //如果更改authorities,记得同时更改AndroidManifest.xml中对应的值
35 | private static String authorities = "baofeng.dcache.com.duke.lib.authorities";
36 | private static Uri uri;
37 |
38 | private static Context context;
39 |
40 | static void setContext(Context context) {
41 | DCache.context = context;
42 | }
43 |
44 | private static void setUri(String authorities) {
45 | uri = Uri.parse(ContentResolver.SCHEME_CONTENT + "://" + authorities);
46 | }
47 |
48 | private DCache() {
49 | setUri(authorities);
50 | }
51 |
52 | private static class I {
53 | private static DCache i = new DCache();
54 | }
55 |
56 | public static DCache get() {
57 | if (context == null) {
58 | throw new IllegalArgumentException("context is not allowed to be null");
59 | }
60 | return I.i;
61 | }
62 |
63 | public static DCache get(String authorities) {
64 | if (context == null) {
65 | throw new IllegalArgumentException("context is not allowed to be null");
66 | }
67 | DCache.authorities = authorities;
68 | setUri(authorities);
69 | return I.i;
70 | }
71 |
72 | private boolean deleteAll() {
73 | int i = context.getContentResolver().delete(uri, null, null);
74 | return i > 0;
75 | }
76 |
77 | private void deleteDataById(int id) {
78 | context.getContentResolver().delete(uri, DSQLiteOpenHelper.DTable.COLUMN_ID + " = ?",
79 | new String[]{String.valueOf(id)});
80 | }
81 |
82 | private boolean deleteDataByKey(String key) {
83 | int i = context.getContentResolver().delete(uri,
84 | DSQLiteOpenHelper.DTable.COLUMN_C_KEY + " = ?",
85 | new String[]{String.valueOf(key)});
86 | return i > 0;
87 | }
88 |
89 | private DData queryData(String key) {
90 | if (DUtils.isEmpty(key)) {
91 | return null;
92 | }
93 | String selection = DSQLiteOpenHelper.DTable.COLUMN_C_KEY + " = ?";
94 | String[] selectionArgs = new String[]{key};
95 | Cursor cursor = context.getContentResolver().query(uri, null,
96 | selection, selectionArgs, null);
97 | if (cursor == null) {
98 | return null;
99 | }
100 | ArrayList list = new ArrayList<>();
101 | DData dData = null;
102 | while (cursor.moveToNext()) {
103 | dData = new DData();
104 | dData.id = cursor.getInt(cursor.getColumnIndex(DSQLiteOpenHelper.DTable.COLUMN_ID));
105 | dData.key = cursor.getString(cursor.getColumnIndex(DSQLiteOpenHelper.DTable.COLUMN_C_KEY));
106 | dData.addTime = cursor.getLong(cursor.getColumnIndex(DSQLiteOpenHelper.DTable.COLUMN_C_ADDTIME));
107 | dData.keepTime = cursor.getLong(cursor.getColumnIndex(DSQLiteOpenHelper.DTable.COLUMN_C_KEEPTIME));
108 | dData.data = cursor.getBlob(cursor.getColumnIndex(DSQLiteOpenHelper.DTable.COLUMN_C_DATA));
109 | list.add(dData);
110 | }
111 | cursor.close();
112 | if (list.size() == 0) {
113 | list = null;
114 | return null;
115 | } else if (list.size() == 1) {
116 | dData = list.get(0);
117 | list.clear();
118 | list = null;
119 | return dData;
120 | } else {
121 | dData = list.get(0);
122 | int size = list.size();
123 | for (int i = 1; i < size; i++) {
124 | deleteDataById(list.get(i).id);
125 | }
126 | list.clear();
127 | list = null;
128 | return dData;
129 | }
130 | }
131 |
132 | private void saveOrUpdate(DData dData) {
133 | if (dData == null) {
134 | return;
135 | }
136 | ContentValues values = new ContentValues();
137 | values.put(DSQLiteOpenHelper.DTable.COLUMN_C_KEY, dData.key);
138 | values.put(DSQLiteOpenHelper.DTable.COLUMN_C_ADDTIME, dData.addTime);
139 | values.put(DSQLiteOpenHelper.DTable.COLUMN_C_KEEPTIME, dData.keepTime);
140 | values.put(DSQLiteOpenHelper.DTable.COLUMN_C_DATA, dData.data);
141 | if (dData.id > 0) {
142 | //修改
143 | values.put(DSQLiteOpenHelper.DTable.COLUMN_ID, dData.id);
144 | context.getContentResolver().update(uri, values,
145 | DSQLiteOpenHelper.DTable.COLUMN_ID + " = ?",
146 | new String[]{String.valueOf(dData.id)});
147 | } else {
148 | //添加
149 | context.getContentResolver().insert(uri, values);
150 | }
151 | }
152 |
153 | private class DData {
154 | int id;
155 | String key;//key字符串
156 | long addTime;//添加时间(毫秒)
157 | long keepTime;//有效保留时间(毫秒)
158 | byte[] data;//二进制数据
159 | }
160 |
161 | //==================以下是对外方法=====================
162 |
163 | public boolean remove(String key) {
164 | if (DUtils.isEmpty(key)) {
165 | return false;
166 | }
167 | return deleteDataByKey(key);
168 | }
169 |
170 | public boolean removeAll() {
171 | return deleteAll();
172 | }
173 |
174 | // =======================================
175 | // ============== byte 数据 读写 =========
176 | // =======================================
177 |
178 | /**
179 | * 保存 byte数据 到 缓存中
180 | *
181 | * @param key 保存的key
182 | * @param data 保存的数据
183 | */
184 | public boolean put(String key, byte[] data) {
185 | return put(key, data, 0L);
186 | }
187 |
188 | /**
189 | * 保存 byte数据 到 缓存中
190 | *
191 | * @param key 保存的key
192 | * @param data 保存的数据
193 | * @param keepTime 保存数据的有效期(毫秒)
194 | */
195 | public boolean put(String key, byte[] data, long keepTime) {
196 | if (DUtils.isEmpty(key) || data == null || data.length == 0) {
197 | return false;
198 | }
199 | if (keepTime < 0) {
200 | keepTime = 0L;
201 | }
202 | DData dData = queryData(key);
203 | if (dData == null) {
204 | //新增
205 | dData = new DData();
206 | dData.key = key;
207 | dData.addTime = System.currentTimeMillis();
208 | dData.keepTime = keepTime;
209 | dData.data = data;
210 | } else {
211 | //更新数据
212 | dData.data = data;
213 | if (keepTime > 0) {
214 | //重新更新保存时间
215 | dData.addTime = System.currentTimeMillis();
216 | dData.keepTime = keepTime;
217 | }
218 | }
219 | saveOrUpdate(dData);
220 | return true;
221 | }
222 |
223 | /**
224 | * 获取 byte 数据
225 | *
226 | * @param key
227 | * @return byte 数据
228 | */
229 | public byte[] getAsBinary(String key) {
230 | if (DUtils.isEmpty(key)) {
231 | return null;
232 | }
233 | DData dData = queryData(key);
234 | if (dData == null) {
235 | return null;
236 | }
237 | //有时间期限,计算是否过期
238 | if (dData.keepTime > 0
239 | && System.currentTimeMillis() > dData.keepTime + dData.addTime) {
240 | deleteDataByKey(dData.key);
241 | return null;
242 | }
243 | //无时间期限,或未过期
244 | return dData.data;
245 | }
246 |
247 | // =======================================
248 | // ============ String数据 读写 ==========
249 | // =======================================
250 |
251 | /**
252 | * 保存 String数据 到 缓存中
253 | *
254 | * @param key 保存的key
255 | * @param data 保存的String数据
256 | */
257 | public boolean put(String key, String data) {
258 | return put(key, data, 0L);
259 | }
260 |
261 | /**
262 | * 保存 String数据 到 缓存中
263 | *
264 | * @param key 保存的key
265 | * @param data 保存的String数据
266 | * @param keepTime 保存数据的有效期(毫秒)
267 | */
268 | public boolean put(String key, String data, long keepTime) {
269 | if (DUtils.isEmpty(data)) {
270 | return false;
271 | }
272 | return put(key, data.getBytes(), keepTime);
273 | }
274 |
275 | /**
276 | * 读取 String数据
277 | *
278 | * @param key
279 | * @return String 数据
280 | */
281 | public String getAsString(String key) {
282 | byte[] bytes = getAsBinary(key);
283 | if (bytes == null || bytes.length == 0) {
284 | return null;
285 | }
286 | return new String(bytes);
287 | }
288 |
289 | // =======================================
290 | // ============= JSONObject 数据 读写 ====
291 | // =======================================
292 |
293 | /**
294 | * 保存 JSONObject数据 到 缓存中
295 | *
296 | * @param key 保存的key
297 | * @param data 保存的JSON数据
298 | */
299 | public boolean put(String key, JSONObject data) {
300 | return put(key, data, 0L);
301 | }
302 |
303 | /**
304 | * 保存 JSONObject数据 到 缓存中
305 | *
306 | * @param key 保存的key
307 | * @param data 保存的JSONObject数据
308 | * @param keepTime 保存数据的有效期(毫秒)
309 | */
310 | public boolean put(String key, JSONObject data, long keepTime) {
311 | if (data == null) {
312 | return false;
313 | }
314 | return put(key, data.toString(), keepTime);
315 | }
316 |
317 | /**
318 | * 读取JSONObject数据
319 | *
320 | * @param key
321 | * @return JSONObject数据
322 | */
323 | public JSONObject getAsJSONObject(String key) throws JSONException {
324 | String json = getAsString(key);
325 | if (DUtils.isEmpty(json)) {
326 | return null;
327 | }
328 | return new JSONObject(json);
329 | }
330 |
331 | // =======================================
332 | // ============ JSONArray 数据 读写 ======
333 | // =======================================
334 |
335 | /**
336 | * 保存 JSONArray数据 到 缓存中
337 | *
338 | * @param key 保存的key
339 | * @param data 保存的JSONArray数据
340 | */
341 | public boolean put(String key, JSONArray data) {
342 | return put(key, data, 0L);
343 | }
344 |
345 | /**
346 | * 保存 JSONArray数据 到 缓存中
347 | *
348 | * @param key 保存的key
349 | * @param data 保存的JSONArray数据
350 | * @param keepTime 保存数据的有效期(毫秒)
351 | */
352 | public boolean put(String key, JSONArray data, long keepTime) {
353 | if (data == null || data.length() == 0) {
354 | return false;
355 | }
356 | return put(key, data.toString(), keepTime);
357 | }
358 |
359 | /**
360 | * 读取JSONArray数据
361 | *
362 | * @param key
363 | * @return JSONArray数据
364 | */
365 | public JSONArray getAsJSONArray(String key) throws JSONException {
366 | String jsonArr = getAsString(key);
367 | if (DUtils.isEmpty(jsonArr)) {
368 | return null;
369 | }
370 | return new JSONArray(jsonArr);
371 | }
372 |
373 | // =======================================
374 | // ============= 序列化 数据 读写 ========
375 | // =======================================
376 |
377 | /**
378 | * 保存 Serializable数据 到 缓存中
379 | *
380 | * @param key 保存的key
381 | * @param data 保存的value
382 | */
383 | public boolean put(String key, Serializable data) {
384 | return put(key, data, 0L);
385 | }
386 |
387 | /**
388 | * 保存 Serializable数据到 缓存中
389 | *
390 | * @param key 保存的key
391 | * @param data 保存的value
392 | * @param keepTime 保存数据的有效期(毫秒)
393 | */
394 | public boolean put(String key, Serializable data, long keepTime) {
395 | if (data == null) {
396 | return false;
397 | }
398 | ByteArrayOutputStream baos = null;
399 | ObjectOutputStream oos = null;
400 | try {
401 | baos = new ByteArrayOutputStream();
402 | oos = new ObjectOutputStream(baos);
403 | oos.writeObject(data);
404 | return put(key, baos.toByteArray(), keepTime);
405 | } catch (Exception e) {
406 | e.printStackTrace();
407 | } finally {
408 | if (oos != null) {
409 | try {
410 | oos.close();
411 | } catch (IOException e) {
412 | e.printStackTrace();
413 | }
414 | }
415 | }
416 | return false;
417 | }
418 |
419 | /**
420 | * 读取 Serializable数据
421 | *
422 | * @param key
423 | * @return Serializable 数据
424 | */
425 | public Object getAsObject(String key) {
426 | byte[] data = getAsBinary(key);
427 | if (data == null) {
428 | return null;
429 | }
430 | ByteArrayInputStream bais = null;
431 | ObjectInputStream ois = null;
432 | try {
433 | bais = new ByteArrayInputStream(data);
434 | ois = new ObjectInputStream(bais);
435 | return ois.readObject();
436 | } catch (Exception e) {
437 | e.printStackTrace();
438 | return null;
439 | } finally {
440 | try {
441 | if (bais != null)
442 | bais.close();
443 | } catch (IOException e) {
444 | e.printStackTrace();
445 | }
446 | try {
447 | if (ois != null)
448 | ois.close();
449 | } catch (IOException e) {
450 | e.printStackTrace();
451 | }
452 | }
453 | }
454 |
455 | // =======================================
456 | // ============== bitmap 数据 读写 =======
457 | // =======================================
458 |
459 | /**
460 | * 保存 bitmap 到 缓存中
461 | *
462 | * @param key 保存的key
463 | * @param data 保存的bitmap数据
464 | */
465 | public boolean put(String key, Bitmap data) {
466 | return put(key, data, 0L);
467 | }
468 |
469 | /**
470 | * 保存 bitmap 到 缓存中
471 | *
472 | * @param key 保存的key
473 | * @param data 保存的 bitmap 数据
474 | * @param keepTime 保存数据的有效期(毫秒)
475 | */
476 | public boolean put(String key, Bitmap data, long keepTime) {
477 | return put(key, DUtils.Bitmap2ByteArray(data), keepTime);
478 | }
479 |
480 | /**
481 | * 读取 bitmap 数据
482 | *
483 | * @param key
484 | * @return bitmap 数据
485 | */
486 | public Bitmap getAsBitmap(String key) {
487 | byte[] bytes = getAsBinary(key);
488 | if (bytes == null) {
489 | return null;
490 | }
491 | return DUtils.ByteArray2Bimap(bytes);
492 | }
493 |
494 | // =======================================
495 | // ============= drawable 数据 读写 ======
496 | // =======================================
497 |
498 | /**
499 | * 保存 drawable 到 缓存中
500 | *
501 | * @param key 保存的key
502 | * @param data 保存的drawable数据
503 | */
504 | public boolean put(String key, Drawable data) {
505 | return put(key, data, 0L);
506 | }
507 |
508 | /**
509 | * 保存 drawable 到 缓存中
510 | *
511 | * @param key 保存的key
512 | * @param data 保存的 drawable 数据
513 | * @param keepTime 保存数据的有效期(毫秒)
514 | */
515 | public boolean put(String key, Drawable data, long keepTime) {
516 | return put(key, DUtils.drawable2Bitmap(data), keepTime);
517 | }
518 |
519 | /**
520 | * 读取 Drawable 数据
521 | *
522 | * @param key
523 | * @return Drawable 数据
524 | */
525 | public Drawable getAsDrawable(String key) {
526 | byte[] bytes = getAsBinary(key);
527 | if (bytes == null) {
528 | return null;
529 | }
530 | return DUtils.bitmap2Drawable(DUtils.ByteArray2Bimap(bytes));
531 | }
532 |
533 | //=========================================
534 | //===hashCode==============================
535 | //=========================================
536 |
537 | public String keyHashCode(Object object) {
538 | if (object == null) {
539 | return null;
540 | }
541 | return String.valueOf(object.hashCode());
542 | }
543 | }
544 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/duke/lib/DContentProvider.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.net.Uri;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.Nullable;
10 |
11 | /**
12 | * @author: duke
13 | * @datetime: 2018-02-09 14:41
14 | * @deacription: 管理数据库操作,支持多线程并发、同步特点
15 | */
16 | public class DContentProvider extends ContentProvider {
17 | private DSQLiteOpenHelper helper = null;
18 |
19 | @Override
20 | public boolean onCreate() {
21 | //初始化数据库工具类
22 | helper = new DSQLiteOpenHelper(getContext());
23 | DCache.setContext(getContext());
24 | //返回true,标记此provider成功初始化
25 | return true;
26 | }
27 |
28 | @Nullable
29 | @Override
30 | public String getType(@NonNull Uri uri) {
31 | return null;
32 | }
33 |
34 | @Nullable
35 | @Override
36 | public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
37 | @Nullable String[] selectionArgs, @Nullable String sortOrder) {
38 | if (getReadableDB() == null) {
39 | return null;
40 | }
41 | return getReadableDB().query(DSQLiteOpenHelper.DTable.TABLE_NAME, projection,
42 | selection, selectionArgs, null, null, sortOrder);
43 | }
44 |
45 | @Nullable
46 | @Override
47 | public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
48 | if (getWritableDB() == null) {
49 | return null;
50 | }
51 | long l = getWritableDB().insert(DSQLiteOpenHelper.DTable.TABLE_NAME, null, values);
52 | return uri;
53 | }
54 |
55 | @Override
56 | public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
57 | if (getWritableDB() == null) {
58 | return 0;
59 | }
60 | return getWritableDB().delete(DSQLiteOpenHelper.DTable.TABLE_NAME, selection, selectionArgs);
61 | }
62 |
63 | @Override
64 | public int update(@NonNull Uri uri, @Nullable ContentValues values,
65 | @Nullable String selection, @Nullable String[] selectionArgs) {
66 | if (getWritableDB() == null) {
67 | return 0;
68 | }
69 | return getWritableDB().update(DSQLiteOpenHelper.DTable.TABLE_NAME, values, selection, selectionArgs);
70 | }
71 |
72 | private SQLiteDatabase getReadableDB() {
73 | if (helper == null) {
74 | return null;
75 | }
76 | return helper.getReadableDatabase();
77 | }
78 |
79 | private SQLiteDatabase getWritableDB() {
80 | if (helper == null) {
81 | return null;
82 | }
83 | return helper.getWritableDatabase();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/duke/lib/DSQLiteOpenHelper.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | /**
8 | * @author: duke
9 | * @datetime: 2018-02-09 14:39
10 | * @deacription:
11 | */
12 | public class DSQLiteOpenHelper extends SQLiteOpenHelper {
13 | private static final String dbName = "DCache.db";
14 | private static final int dbVersion = 1;
15 |
16 | public DSQLiteOpenHelper(Context context) {
17 | super(context, dbName, null, dbVersion);
18 | }
19 |
20 | @Override
21 | public void onCreate(SQLiteDatabase db) {
22 | db.execSQL(DTable.createTableSQL());
23 | }
24 |
25 | @Override
26 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
27 | throw new IllegalArgumentException("not need upgrade");
28 | }
29 |
30 | /**
31 | * @author: duke
32 | * @datetime: 2018-02-09 15:08
33 | * @deacription: 表结构
34 | */
35 | public static class DTable {
36 | public static final String TABLE_NAME = "tblDCache";//表名
37 | public static final String COLUMN_ID = "_id";//id,自动增长
38 | public static final String COLUMN_C_KEY = "cKey";//数据记录key,唯一键
39 | public static final String COLUMN_C_ADDTIME = "cAddTime";//数据记录添加时间(毫秒)
40 | public static final String COLUMN_C_KEEPTIME = "cKeepTime";//数据记录保存期限时间(毫秒)
41 | public static final String COLUMN_C_DATA = "cData";//数据记录内容(二进制形式)
42 |
43 | public static String createTableSQL() {
44 | return "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
45 | + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
46 | + COLUMN_C_KEY + " VARCHAR UNIQUE, "
47 | + COLUMN_C_ADDTIME + " INTEGER, "
48 | + COLUMN_C_KEEPTIME + " INTEGER, "
49 | + COLUMN_C_DATA + " BLOB)";
50 | }
51 |
52 | public static String alterTableSQL() {
53 | return "ALTER TABLE " + TABLE_NAME + " ADD COLUMN xxx varchar";
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/duke/lib/DUtils.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 | import android.graphics.Canvas;
6 | import android.graphics.PixelFormat;
7 | import android.graphics.drawable.BitmapDrawable;
8 | import android.graphics.drawable.Drawable;
9 |
10 | import java.io.ByteArrayOutputStream;
11 |
12 | /**
13 | * @author duke
14 | * @dateTime 2018-02-10 08:06
15 | * @description
16 | */
17 | public class DUtils {
18 | static boolean isEmpty(String content) {
19 | return content == null
20 | || "".equals(content.trim())
21 | || content.trim().length() == 0;
22 | }
23 |
24 |
25 | /*
26 | * Bitmap → byte[]
27 | */
28 | public static byte[] Bitmap2ByteArray(Bitmap bm) {
29 | if (bm == null || bm.isRecycled()) {
30 | return null;
31 | }
32 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
33 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
34 | return baos.toByteArray();
35 | }
36 |
37 | /*
38 | * byte[] → Bitmap
39 | */
40 | public static Bitmap ByteArray2Bimap(byte[] b) {
41 | if (b == null || b.length == 0) {
42 | return null;
43 | }
44 | return BitmapFactory.decodeByteArray(b, 0, b.length);
45 | }
46 |
47 | /*
48 | * Drawable → Bitmap
49 | */
50 | public static Bitmap drawable2Bitmap(Drawable drawable) {
51 | if (drawable == null) {
52 | return null;
53 | }
54 | // 取 drawable 的长宽
55 | int w = drawable.getMinimumWidth();
56 | int h = drawable.getMinimumHeight();
57 | // 取 drawable 的颜色格式
58 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
59 | // 建立对应 bitmap
60 | Bitmap bitmap = Bitmap.createBitmap(w, h, config);
61 | // 建立对应 bitmap 的画布
62 | Canvas canvas = new Canvas(bitmap);
63 | drawable.setBounds(0, 0, w, h);
64 | // 把 drawable 内容画到画布中
65 | drawable.draw(canvas);
66 | return bitmap;
67 | }
68 |
69 | /*
70 | * Bitmap → Drawable
71 | */
72 | @SuppressWarnings("deprecation")
73 | public static Drawable bitmap2Drawable(Bitmap bm) {
74 | if (bm == null || bm.isRecycled()) {
75 | return null;
76 | }
77 | BitmapDrawable bd = new BitmapDrawable(bm);
78 | bd.setTargetDensity(bm.getDensity());
79 | return new BitmapDrawable(bm);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | lib
3 |
4 |
--------------------------------------------------------------------------------
/lib/src/test/java/com/duke/lib/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duke.lib;
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 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':lib'
2 |
--------------------------------------------------------------------------------