├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── README.md ├── SHARE.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yjx │ │ └── share │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yjx │ │ └── share │ │ ├── MainActivity.java │ │ ├── People.java │ │ └── YjxApplication.java │ └── res │ ├── drawable │ └── dd.png │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── library.iml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yjx │ │ └── sharelibrary │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yjx │ │ └── sharelibrary │ │ ├── DiskLruCache.java │ │ ├── Share.java │ │ └── cache │ │ ├── Cache.java │ │ ├── DiskCache.java │ │ └── MemoryCache.java │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SHARE -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.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 | 22 | 23 | 24 | 25 | 26 | 1.7 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ##背景 3 | 想必大家一定用过 sharedpreferences 吧!就我个人而言,特别讨厌每次 put 完数据还要 commit。对 我就是这么懒!哈哈。另外,sharedpreferences 不能存类,集合和bitmap等数据!这点也让人非常不爽啊!所以,我就在这个美好的星期天撸了名为 SHARE 的工具类用来替代 sharedpreferences。 4 | 5 | --- 6 | 7 | ##项目介绍 8 | ### 整体架构 9 | 先来看一下,整体架构图(画的不好请大家见谅): 10 | 11 | ![图片](http://ww4.sinaimg.cn/large/a174c633gw1esfdojri3oj20f009gabi.jpg) 12 | 13 | 从图中,我们可以了解到,当我们 put 数据的时候,我们同时存入到 内存和和sd卡中。读取的时候,优先从内存中获取,如果内存中没有,则从sd中获取。如果两者都没有,则使用用户自己设置的默认值! 14 | 15 | ### 代码介绍 16 | 17 | 下来看一下代码目录结构: 18 | ![图片](http://ww1.sinaimg.cn/large/a174c633gw1esffncc9wdj20hj049jrl.jpg) 19 | 20 | - DiskLruCache:硬盘缓存的解决方案(非Google官方编写,但获得官方认证。[地址](android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java)) 21 | - Cache:接口。抽象了对数据的操作 22 | - MemoryCache:内存缓存,实现了Cache接口 23 | - DiskCache:硬盘缓存,同样实现了Cache接口 24 | - Share:这个类就是我们使用的!他主要是提供了 put 和 get两种方法!其实就是对 MemoryCache 和 DiskCache 两个类的操作! 25 | 26 | ### 使用 27 | 28 | 在 Application中初始化: 29 | 30 | @Override 31 | public void onCreate() { 32 | super.onCreate(); 33 | File file = new File(Environment.getExternalStorageDirectory().toString() + File.separator + "sample"); 34 | if (!file.exists()) { 35 | file.mkdirs(); 36 | } 37 | Share.init("CACHE", 10 * 1024, file.toString()); 38 | } 39 | 之后,你就可以任意的使用它了! 40 | 41 | //设置字符串 42 | Share.putString("str", "你好啊"); 43 | //设置int 44 | Share.putInt("int", 1); 45 | //设置boolean 46 | Share.putBoolean("boolean", true); 47 | //设置double 48 | Share.putDouble("double", 2.1d); 49 | //设置long 50 | Share.putLong("long", 20000); 51 | //设置flot 52 | Share.putFloat("float", 2.2f); 53 | //设置类 54 | Share.putObject("obj", people); 55 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dd); 56 | //设置bitmap 57 | Share.putBitmap("bitmap", bitmap); 58 | //设置集合 59 | Share.putObject("list", items); 60 | --- 61 | 62 | //得到字符串 63 | String str=Share.getString("str"); 64 | //得到double 65 | double dd=Share.getDouble("double", 0.0d); 66 | //得到int 67 | int value=Share.getInt("int", 0); 68 | //得到float 69 | float ff=Share.getFloat("float", 0.0f); 70 | //得到bitmap 71 | Bitmap map=Share.getBitmap("bitmap"); 72 | //得到集合 73 | List copy= (List) Share.getObject("list"); 74 | ..... 75 | 76 | 使用就是如此简单! 77 | 78 | ### 近期要完成的新功能 79 | 80 | 1.对泛型的支持. 81 | 82 | --- 83 | ##项目地址 84 | 85 | - [GitHub](https://github.com/yjxandroid/SHARE) 86 | 87 | 希望这个项目对大家有用。也希望多 star .同时也能多多提出修改意见!不管是对项目本身还是代码!!!! 88 | 89 | -------------------------------------------------------------------------------- /SHARE.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | applicationId "com.yjx.share" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.1.0' 25 | compile project(':library') 26 | } 27 | -------------------------------------------------------------------------------- /app/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 /Soft/android-sdk-macosx/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/yjx/share/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yjx.share; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjx/share/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yjx.share; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.support.v7.app.ActionBarActivity; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.yjx.sharelibrary.Share; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | 16 | public class MainActivity extends ActionBarActivity { 17 | List items = new ArrayList(); 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | items.add("item1"); 24 | items.add("item2"); 25 | items.add("item3"); 26 | items.add("item4"); 27 | items.add("item5"); 28 | TextView textView1 = (TextView) findViewById(R.id.tv); 29 | TextView textView2 = (TextView) findViewById(R.id.tv1); 30 | TextView textView3 = (TextView) findViewById(R.id.tv2); 31 | TextView textView4 = (TextView) findViewById(R.id.tv3); 32 | TextView textView5 = (TextView) findViewById(R.id.tv4); 33 | TextView textView6 = (TextView) findViewById(R.id.tv5); 34 | ImageView iv = (ImageView) findViewById(R.id.iv); 35 | People people = new People(20, "yjx"); 36 | //设置字符串 37 | Share.putString("str", "你好啊"); 38 | //设置int 39 | Share.putInt("int", 1); 40 | //设置boolean 41 | Share.putBoolean("boolean", true); 42 | //设置double 43 | Share.putDouble("double", 2.1d); 44 | //设置long 45 | Share.putLong("long", 20000); 46 | //设置flot 47 | Share.putFloat("float", 2.2f); 48 | //设置类 49 | Share.putObject("obj", people); 50 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dd); 51 | //设置bitmap 52 | Share.putBitmap("bitmap", bitmap); 53 | //设置集合 54 | Share.putObject("list", items); 55 | 56 | //得到字符串 57 | String str=Share.getString("str"); 58 | //得到double 59 | double dd=Share.getDouble("double", 0.0d); 60 | //得到int 61 | int value=Share.getInt("int", 0); 62 | //得到float 63 | float ff=Share.getFloat("float", 0.0f); 64 | //得到bitmap 65 | Bitmap map=Share.getBitmap("bitmap"); 66 | //得到集合 67 | List copy= (List) Share.getObject("list"); 68 | 69 | textView1.setText(Share.getString("str")); 70 | textView2.setText(Share.getInt("int", 0) + ""); 71 | textView3.setText(Share.getDouble("double", 0.0d) + ""); 72 | textView4.setText(Share.getFloat("float", 0.0f) + ""); 73 | textView5.setText(Share.getLong("long", 0) + ""); 74 | People pp = (People) Share.getObject("obj"); 75 | textView6.setText(pp.getAge() + " " + pp.getName()); 76 | iv.setImageBitmap(Share.getBitmap("bitmap")); 77 | 78 | // Share.clearData(); 79 | 80 | // textView2.setText(Share.getInt("int", 0) + ""); 81 | 82 | Share.putObject("list", items); 83 | 84 | 85 | for (int i=0;i 6 | 7 | 12 | 17 | 22 | 27 | 32 | 33 | 38 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjxandroid/SHARE/c3d3547deb92f2cfc642e979ce26d96dc9d5b5f9/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjxandroid/SHARE/c3d3547deb92f2cfc642e979ce26d96dc9d5b5f9/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjxandroid/SHARE/c3d3547deb92f2cfc642e979ce26d96dc9d5b5f9/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjxandroid/SHARE/c3d3547deb92f2cfc642e979ce26d96dc9d5b5f9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SHARE 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjxandroid/SHARE/c3d3547deb92f2cfc642e979ce26d96dc9d5b5f9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 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-2.2.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 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 21 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile 'com.android.support:appcompat-v7:22.1.0' 24 | } 25 | -------------------------------------------------------------------------------- /library/library.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /library/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 /Soft/android-sdk-macosx/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 | -------------------------------------------------------------------------------- /library/src/androidTest/java/com/yjx/sharelibrary/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yjx.sharelibrary; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/java/com/yjx/sharelibrary/DiskLruCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.yjx.sharelibrary; 18 | 19 | import java.io.BufferedInputStream; 20 | import java.io.BufferedWriter; 21 | import java.io.Closeable; 22 | import java.io.EOFException; 23 | import java.io.File; 24 | import java.io.FileInputStream; 25 | import java.io.FileNotFoundException; 26 | import java.io.FileOutputStream; 27 | import java.io.FileWriter; 28 | import java.io.FilterOutputStream; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.io.InputStreamReader; 32 | import java.io.OutputStream; 33 | import java.io.OutputStreamWriter; 34 | import java.io.Reader; 35 | import java.io.StringWriter; 36 | import java.io.Writer; 37 | import java.lang.reflect.Array; 38 | import java.nio.charset.Charset; 39 | import java.util.ArrayList; 40 | import java.util.Arrays; 41 | import java.util.Iterator; 42 | import java.util.LinkedHashMap; 43 | import java.util.Map; 44 | import java.util.concurrent.Callable; 45 | import java.util.concurrent.ExecutorService; 46 | import java.util.concurrent.LinkedBlockingQueue; 47 | import java.util.concurrent.ThreadPoolExecutor; 48 | import java.util.concurrent.TimeUnit; 49 | 50 | /** 51 | ****************************************************************************** 52 | * Taken from the JB source code, can be found in: 53 | * libcore/luni/src/main/java/libcore/io/DiskLruCache.java 54 | * or direct link: 55 | * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java 56 | ****************************************************************************** 57 | * 58 | * A cache that uses a bounded amount of space on a filesystem. Each cache 59 | * entry has a string key and a fixed number of values. Values are byte 60 | * sequences, accessible as streams or files. Each value must be between {@code 61 | * 0} and {@code Integer.MAX_VALUE} bytes in length. 62 | * 63 | *

The cache stores its data in a directory on the filesystem. This 64 | * directory must be exclusive to the cache; the cache may delete or overwrite 65 | * files from its directory. It is an error for multiple processes to use the 66 | * same cache directory at the same time. 67 | * 68 | *

This cache limits the number of bytes that it will store on the 69 | * filesystem. When the number of stored bytes exceeds the limit, the cache will 70 | * remove entries in the background until the limit is satisfied. The limit is 71 | * not strict: the cache may temporarily exceed it while waiting for files to be 72 | * deleted. The limit does not include filesystem overhead or the cache 73 | * journal so space-sensitive applications should set a conservative limit. 74 | * 75 | *

Clients call {@link #edit} to create or update the values of an entry. An 76 | * entry may have only one editor at one time; if a value is not available to be 77 | * edited then {@link #edit} will return null. 78 | *

    79 | *
  • When an entry is being created it is necessary to 80 | * supply a full set of values; the empty value should be used as a 81 | * placeholder if necessary. 82 | *
  • When an entry is being edited, it is not necessary 83 | * to supply data for every value; values default to their previous 84 | * value. 85 | *
86 | * Every {@link #edit} call must be matched by a call to {@link Editor#commit} 87 | * or {@link Editor#abort}. Committing is atomic: a read observes the full set 88 | * of values as they were before or after the commit, but never a mix of values. 89 | * 90 | *

Clients call {@link #get} to read a snapshot of an entry. The read will 91 | * observe the value at the time that {@link #get} was called. Updates and 92 | * removals after the call do not impact ongoing reads. 93 | * 94 | *

This class is tolerant of some I/O errors. If files are missing from the 95 | * filesystem, the corresponding entries will be dropped from the cache. If 96 | * an error occurs while writing a cache value, the edit will fail silently. 97 | * Callers should handle other problems by catching {@code IOException} and 98 | * responding appropriately. 99 | */ 100 | public final class DiskLruCache implements Closeable { 101 | static final String JOURNAL_FILE = "journal"; 102 | static final String JOURNAL_FILE_TMP = "journal.tmp"; 103 | static final String MAGIC = "libcore.io.DiskLruCache"; 104 | static final String VERSION_1 = "1"; 105 | static final long ANY_SEQUENCE_NUMBER = -1; 106 | private static final String CLEAN = "CLEAN"; 107 | private static final String DIRTY = "DIRTY"; 108 | private static final String REMOVE = "REMOVE"; 109 | private static final String READ = "READ"; 110 | 111 | private static final Charset UTF_8 = Charset.forName("UTF-8"); 112 | private static final int IO_BUFFER_SIZE = 8 * 1024; 113 | 114 | /* 115 | * This cache uses a journal file named "journal". A typical journal file 116 | * looks like this: 117 | * libcore.io.DiskLruCache 118 | * 1 119 | * 100 120 | * 2 121 | * 122 | * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 123 | * DIRTY 335c4c6028171cfddfbaae1a9c313c52 124 | * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 125 | * REMOVE 335c4c6028171cfddfbaae1a9c313c52 126 | * DIRTY 1ab96a171faeeee38496d8b330771a7a 127 | * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 128 | * READ 335c4c6028171cfddfbaae1a9c313c52 129 | * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 130 | * 131 | * The first five lines of the journal form its header. They are the 132 | * constant string "libcore.io.DiskLruCache", the disk cache's version, 133 | * the application's version, the value count, and a blank line. 134 | * 135 | * Each of the subsequent lines in the file is a record of the state of a 136 | * cache entry. Each line contains space-separated values: a state, a key, 137 | * and optional state-specific values. 138 | * o DIRTY lines track that an entry is actively being created or updated. 139 | * Every successful DIRTY action should be followed by a CLEAN or REMOVE 140 | * action. DIRTY lines without a matching CLEAN or REMOVE indicate that 141 | * temporary files may need to be deleted. 142 | * o CLEAN lines track a cache entry that has been successfully published 143 | * and may be read. A publish line is followed by the lengths of each of 144 | * its values. 145 | * o READ lines track accesses for LRU. 146 | * o REMOVE lines track entries that have been deleted. 147 | * 148 | * The journal file is appended to as cache operations occur. The journal may 149 | * occasionally be compacted by dropping redundant lines. A temporary file named 150 | * "journal.tmp" will be used during compaction; that file should be deleted if 151 | * it exists when the cache is opened. 152 | */ 153 | 154 | private final File directory; 155 | private final File journalFile; 156 | private final File journalFileTmp; 157 | private final int appVersion; 158 | private final long maxSize; 159 | private final int valueCount; 160 | private long size = 0; 161 | private Writer journalWriter; 162 | private final LinkedHashMap lruEntries 163 | = new LinkedHashMap(0, 0.75f, true); 164 | private int redundantOpCount; 165 | 166 | /** 167 | * To differentiate between old and current snapshots, each entry is given 168 | * a sequence number each time an edit is committed. A snapshot is stale if 169 | * its sequence number is not equal to its entry's sequence number. 170 | */ 171 | private long nextSequenceNumber = 0; 172 | 173 | /* From java.util.Arrays */ 174 | @SuppressWarnings("unchecked") 175 | private static T[] copyOfRange(T[] original, int start, int end) { 176 | final int originalLength = original.length; // For exception priority compatibility. 177 | if (start > end) { 178 | throw new IllegalArgumentException(); 179 | } 180 | if (start < 0 || start > originalLength) { 181 | throw new ArrayIndexOutOfBoundsException(); 182 | } 183 | final int resultLength = end - start; 184 | final int copyLength = Math.min(resultLength, originalLength - start); 185 | final T[] result = (T[]) Array 186 | .newInstance(original.getClass().getComponentType(), resultLength); 187 | System.arraycopy(original, start, result, 0, copyLength); 188 | return result; 189 | } 190 | 191 | /** 192 | * Returns the remainder of 'reader' as a string, closing it when done. 193 | */ 194 | public static String readFully(Reader reader) throws IOException { 195 | try { 196 | StringWriter writer = new StringWriter(); 197 | char[] buffer = new char[1024]; 198 | int count; 199 | while ((count = reader.read(buffer)) != -1) { 200 | writer.write(buffer, 0, count); 201 | } 202 | return writer.toString(); 203 | } finally { 204 | reader.close(); 205 | } 206 | } 207 | 208 | /** 209 | * Returns the ASCII characters up to but not including the next "\r\n", or 210 | * "\n". 211 | * 212 | * @throws EOFException if the stream is exhausted before the next newline 213 | * character. 214 | */ 215 | public static String readAsciiLine(InputStream in) throws IOException { 216 | // TODO: support UTF-8 here instead 217 | 218 | StringBuilder result = new StringBuilder(80); 219 | while (true) { 220 | int c = in.read(); 221 | if (c == -1) { 222 | throw new EOFException(); 223 | } else if (c == '\n') { 224 | break; 225 | } 226 | 227 | result.append((char) c); 228 | } 229 | int length = result.length(); 230 | if (length > 0 && result.charAt(length - 1) == '\r') { 231 | result.setLength(length - 1); 232 | } 233 | return result.toString(); 234 | } 235 | 236 | /** 237 | * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. 238 | */ 239 | public static void closeQuietly(Closeable closeable) { 240 | if (closeable != null) { 241 | try { 242 | closeable.close(); 243 | } catch (RuntimeException rethrown) { 244 | throw rethrown; 245 | } catch (Exception ignored) { 246 | } 247 | } 248 | } 249 | 250 | /** 251 | * Recursively delete everything in {@code dir}. 252 | */ 253 | // TODO: this should specify paths as Strings rather than as Files 254 | public static void deleteContents(File dir) throws IOException { 255 | File[] files = dir.listFiles(); 256 | if (files == null) { 257 | throw new IllegalArgumentException("not a directory: " + dir); 258 | } 259 | for (File file : files) { 260 | if (file.isDirectory()) { 261 | deleteContents(file); 262 | } 263 | if (!file.delete()) { 264 | throw new IOException("failed to delete file: " + file); 265 | } 266 | } 267 | } 268 | 269 | /** This cache uses a single background thread to evict entries. */ 270 | private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, 271 | 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); 272 | private final Callable cleanupCallable = new Callable() { 273 | @Override public Void call() throws Exception { 274 | synchronized (DiskLruCache.this) { 275 | if (journalWriter == null) { 276 | return null; // closed 277 | } 278 | trimToSize(); 279 | if (journalRebuildRequired()) { 280 | rebuildJournal(); 281 | redundantOpCount = 0; 282 | } 283 | } 284 | return null; 285 | } 286 | }; 287 | 288 | private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { 289 | this.directory = directory; 290 | this.appVersion = appVersion; 291 | this.journalFile = new File(directory, JOURNAL_FILE); 292 | this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP); 293 | this.valueCount = valueCount; 294 | this.maxSize = maxSize; 295 | } 296 | 297 | /** 298 | * Opens the cache in {@code directory}, creating a cache if none exists 299 | * there. 300 | * 301 | * @param directory a writable directory 302 | * @param appVersion 303 | * @param valueCount the number of values per cache entry. Must be positive. 304 | * @param maxSize the maximum number of bytes this cache should use to store 305 | * @throws IOException if reading or writing the cache directory fails 306 | */ 307 | public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) 308 | throws IOException { 309 | if (maxSize <= 0) { 310 | throw new IllegalArgumentException("maxSize <= 0"); 311 | } 312 | if (valueCount <= 0) { 313 | throw new IllegalArgumentException("valueCount <= 0"); 314 | } 315 | 316 | // prefer to pick up where we left off 317 | DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); 318 | if (cache.journalFile.exists()) { 319 | try { 320 | cache.readJournal(); 321 | cache.processJournal(); 322 | cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), 323 | IO_BUFFER_SIZE); 324 | return cache; 325 | } catch (IOException journalIsCorrupt) { 326 | // System.logW("DiskLruCache " + directory + " is corrupt: " 327 | // + journalIsCorrupt.getMessage() + ", removing"); 328 | cache.delete(); 329 | } 330 | } 331 | 332 | // create a new empty cache 333 | directory.mkdirs(); 334 | cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); 335 | cache.rebuildJournal(); 336 | return cache; 337 | } 338 | 339 | private void readJournal() throws IOException { 340 | InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); 341 | try { 342 | String magic = readAsciiLine(in); 343 | String version = readAsciiLine(in); 344 | String appVersionString = readAsciiLine(in); 345 | String valueCountString = readAsciiLine(in); 346 | String blank = readAsciiLine(in); 347 | if (!MAGIC.equals(magic) 348 | || !VERSION_1.equals(version) 349 | || !Integer.toString(appVersion).equals(appVersionString) 350 | || !Integer.toString(valueCount).equals(valueCountString) 351 | || !"".equals(blank)) { 352 | throw new IOException("unexpected journal header: [" 353 | + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); 354 | } 355 | 356 | while (true) { 357 | try { 358 | readJournalLine(readAsciiLine(in)); 359 | } catch (EOFException endOfJournal) { 360 | break; 361 | } 362 | } 363 | } finally { 364 | closeQuietly(in); 365 | } 366 | } 367 | 368 | private void readJournalLine(String line) throws IOException { 369 | String[] parts = line.split(" "); 370 | if (parts.length < 2) { 371 | throw new IOException("unexpected journal line: " + line); 372 | } 373 | 374 | String key = parts[1]; 375 | if (parts[0].equals(REMOVE) && parts.length == 2) { 376 | lruEntries.remove(key); 377 | return; 378 | } 379 | 380 | Entry entry = lruEntries.get(key); 381 | if (entry == null) { 382 | entry = new Entry(key); 383 | lruEntries.put(key, entry); 384 | } 385 | 386 | if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { 387 | entry.readable = true; 388 | entry.currentEditor = null; 389 | entry.setLengths(copyOfRange(parts, 2, parts.length)); 390 | } else if (parts[0].equals(DIRTY) && parts.length == 2) { 391 | entry.currentEditor = new Editor(entry); 392 | } else if (parts[0].equals(READ) && parts.length == 2) { 393 | // this work was already done by calling lruEntries.get() 394 | } else { 395 | throw new IOException("unexpected journal line: " + line); 396 | } 397 | } 398 | 399 | /** 400 | * Computes the initial size and collects garbage as a part of opening the 401 | * cache. Dirty entries are assumed to be inconsistent and will be deleted. 402 | */ 403 | private void processJournal() throws IOException { 404 | deleteIfExists(journalFileTmp); 405 | for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { 406 | Entry entry = i.next(); 407 | if (entry.currentEditor == null) { 408 | for (int t = 0; t < valueCount; t++) { 409 | size += entry.lengths[t]; 410 | } 411 | } else { 412 | entry.currentEditor = null; 413 | for (int t = 0; t < valueCount; t++) { 414 | deleteIfExists(entry.getCleanFile(t)); 415 | deleteIfExists(entry.getDirtyFile(t)); 416 | } 417 | i.remove(); 418 | } 419 | } 420 | } 421 | 422 | /** 423 | * Creates a new journal that omits redundant information. This replaces the 424 | * current journal if it exists. 425 | */ 426 | private synchronized void rebuildJournal() throws IOException { 427 | if (journalWriter != null) { 428 | journalWriter.close(); 429 | } 430 | 431 | Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); 432 | writer.write(MAGIC); 433 | writer.write("\n"); 434 | writer.write(VERSION_1); 435 | writer.write("\n"); 436 | writer.write(Integer.toString(appVersion)); 437 | writer.write("\n"); 438 | writer.write(Integer.toString(valueCount)); 439 | writer.write("\n"); 440 | writer.write("\n"); 441 | 442 | for (Entry entry : lruEntries.values()) { 443 | if (entry.currentEditor != null) { 444 | writer.write(DIRTY + ' ' + entry.key + '\n'); 445 | } else { 446 | writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); 447 | } 448 | } 449 | 450 | writer.close(); 451 | journalFileTmp.renameTo(journalFile); 452 | journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); 453 | } 454 | 455 | private static void deleteIfExists(File file) throws IOException { 456 | // try { 457 | // Libcore.os.remove(file.getPath()); 458 | // } catch (ErrnoException errnoException) { 459 | // if (errnoException.errno != OsConstants.ENOENT) { 460 | // throw errnoException.rethrowAsIOException(); 461 | // } 462 | // } 463 | if (file.exists() && !file.delete()) { 464 | throw new IOException(); 465 | } 466 | } 467 | 468 | /** 469 | * Returns a snapshot of the entry named {@code key}, or null if it doesn't 470 | * exist is not currently readable. If a value is returned, it is moved to 471 | * the head of the LRU queue. 472 | */ 473 | public synchronized Snapshot get(String key) throws IOException { 474 | checkNotClosed(); 475 | validateKey(key); 476 | Entry entry = lruEntries.get(key); 477 | if (entry == null) { 478 | return null; 479 | } 480 | 481 | if (!entry.readable) { 482 | return null; 483 | } 484 | 485 | /* 486 | * Open all streams eagerly to guarantee that we see a single published 487 | * snapshot. If we opened streams lazily then the streams could come 488 | * from different edits. 489 | */ 490 | InputStream[] ins = new InputStream[valueCount]; 491 | try { 492 | for (int i = 0; i < valueCount; i++) { 493 | ins[i] = new FileInputStream(entry.getCleanFile(i)); 494 | } 495 | } catch (FileNotFoundException e) { 496 | // a file must have been deleted manually! 497 | return null; 498 | } 499 | 500 | redundantOpCount++; 501 | journalWriter.append(READ + ' ' + key + '\n'); 502 | if (journalRebuildRequired()) { 503 | executorService.submit(cleanupCallable); 504 | } 505 | 506 | return new Snapshot(key, entry.sequenceNumber, ins); 507 | } 508 | 509 | /** 510 | * Returns an editor for the entry named {@code key}, or null if another 511 | * edit is in progress. 512 | */ 513 | public Editor edit(String key) throws IOException { 514 | return edit(key, ANY_SEQUENCE_NUMBER); 515 | } 516 | 517 | private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { 518 | checkNotClosed(); 519 | validateKey(key); 520 | Entry entry = lruEntries.get(key); 521 | if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER 522 | && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { 523 | return null; // snapshot is stale 524 | } 525 | if (entry == null) { 526 | entry = new Entry(key); 527 | lruEntries.put(key, entry); 528 | } else if (entry.currentEditor != null) { 529 | return null; // another edit is in progress 530 | } 531 | 532 | Editor editor = new Editor(entry); 533 | entry.currentEditor = editor; 534 | 535 | // flush the journal before creating files to prevent file leaks 536 | journalWriter.write(DIRTY + ' ' + key + '\n'); 537 | journalWriter.flush(); 538 | return editor; 539 | } 540 | 541 | /** 542 | * Returns the directory where this cache stores its data. 543 | */ 544 | public File getDirectory() { 545 | return directory; 546 | } 547 | 548 | /** 549 | * Returns the maximum number of bytes that this cache should use to store 550 | * its data. 551 | */ 552 | public long maxSize() { 553 | return maxSize; 554 | } 555 | 556 | /** 557 | * Returns the number of bytes currently being used to store the values in 558 | * this cache. This may be greater than the max size if a background 559 | * deletion is pending. 560 | */ 561 | public synchronized long size() { 562 | return size; 563 | } 564 | 565 | private synchronized void completeEdit(Editor editor, boolean success) throws IOException { 566 | Entry entry = editor.entry; 567 | if (entry.currentEditor != editor) { 568 | throw new IllegalStateException(); 569 | } 570 | 571 | // if this edit is creating the entry for the first time, every index must have a value 572 | if (success && !entry.readable) { 573 | for (int i = 0; i < valueCount; i++) { 574 | if (!entry.getDirtyFile(i).exists()) { 575 | editor.abort(); 576 | throw new IllegalStateException("edit didn't create file " + i); 577 | } 578 | } 579 | } 580 | 581 | for (int i = 0; i < valueCount; i++) { 582 | File dirty = entry.getDirtyFile(i); 583 | if (success) { 584 | if (dirty.exists()) { 585 | File clean = entry.getCleanFile(i); 586 | dirty.renameTo(clean); 587 | long oldLength = entry.lengths[i]; 588 | long newLength = clean.length(); 589 | entry.lengths[i] = newLength; 590 | size = size - oldLength + newLength; 591 | } 592 | } else { 593 | deleteIfExists(dirty); 594 | } 595 | } 596 | 597 | redundantOpCount++; 598 | entry.currentEditor = null; 599 | if (entry.readable | success) { 600 | entry.readable = true; 601 | journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); 602 | if (success) { 603 | entry.sequenceNumber = nextSequenceNumber++; 604 | } 605 | } else { 606 | lruEntries.remove(entry.key); 607 | journalWriter.write(REMOVE + ' ' + entry.key + '\n'); 608 | } 609 | 610 | if (size > maxSize || journalRebuildRequired()) { 611 | executorService.submit(cleanupCallable); 612 | } 613 | } 614 | 615 | /** 616 | * We only rebuild the journal when it will halve the size of the journal 617 | * and eliminate at least 2000 ops. 618 | */ 619 | private boolean journalRebuildRequired() { 620 | final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000; 621 | return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD 622 | && redundantOpCount >= lruEntries.size(); 623 | } 624 | 625 | /** 626 | * Drops the entry for {@code key} if it exists and can be removed. Entries 627 | * actively being edited cannot be removed. 628 | * 629 | * @return true if an entry was removed. 630 | */ 631 | public synchronized boolean remove(String key) throws IOException { 632 | checkNotClosed(); 633 | validateKey(key); 634 | Entry entry = lruEntries.get(key); 635 | if (entry == null || entry.currentEditor != null) { 636 | return false; 637 | } 638 | 639 | for (int i = 0; i < valueCount; i++) { 640 | File file = entry.getCleanFile(i); 641 | if (!file.delete()) { 642 | throw new IOException("failed to delete " + file); 643 | } 644 | size -= entry.lengths[i]; 645 | entry.lengths[i] = 0; 646 | } 647 | 648 | redundantOpCount++; 649 | journalWriter.append(REMOVE + ' ' + key + '\n'); 650 | lruEntries.remove(key); 651 | 652 | if (journalRebuildRequired()) { 653 | executorService.submit(cleanupCallable); 654 | } 655 | 656 | return true; 657 | } 658 | 659 | /** 660 | * Returns true if this cache has been closed. 661 | */ 662 | public boolean isClosed() { 663 | return journalWriter == null; 664 | } 665 | 666 | private void checkNotClosed() { 667 | if (journalWriter == null) { 668 | throw new IllegalStateException("cache is closed"); 669 | } 670 | } 671 | 672 | /** 673 | * Force buffered operations to the filesystem. 674 | */ 675 | public synchronized void flush() throws IOException { 676 | checkNotClosed(); 677 | trimToSize(); 678 | journalWriter.flush(); 679 | } 680 | 681 | /** 682 | * Closes this cache. Stored values will remain on the filesystem. 683 | */ 684 | public synchronized void close() throws IOException { 685 | if (journalWriter == null) { 686 | return; // already closed 687 | } 688 | for (Entry entry : new ArrayList(lruEntries.values())) { 689 | if (entry.currentEditor != null) { 690 | entry.currentEditor.abort(); 691 | } 692 | } 693 | trimToSize(); 694 | journalWriter.close(); 695 | journalWriter = null; 696 | } 697 | 698 | private void trimToSize() throws IOException { 699 | while (size > maxSize) { 700 | // Map.Entry toEvict = lruEntries.eldest(); 701 | final Map.Entry toEvict = lruEntries.entrySet().iterator().next(); 702 | remove(toEvict.getKey()); 703 | } 704 | } 705 | 706 | /** 707 | * Closes the cache and deletes all of its stored values. This will delete 708 | * all files in the cache directory including files that weren't created by 709 | * the cache. 710 | */ 711 | public void delete() throws IOException { 712 | close(); 713 | deleteContents(directory); 714 | } 715 | 716 | private void validateKey(String key) { 717 | if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { 718 | throw new IllegalArgumentException( 719 | "keys must not contain spaces or newlines: \"" + key + "\""); 720 | } 721 | } 722 | 723 | private static String inputStreamToString(InputStream in) throws IOException { 724 | return readFully(new InputStreamReader(in, UTF_8)); 725 | } 726 | 727 | /** 728 | * A snapshot of the values for an entry. 729 | */ 730 | public final class Snapshot implements Closeable { 731 | private final String key; 732 | private final long sequenceNumber; 733 | private final InputStream[] ins; 734 | 735 | private Snapshot(String key, long sequenceNumber, InputStream[] ins) { 736 | this.key = key; 737 | this.sequenceNumber = sequenceNumber; 738 | this.ins = ins; 739 | } 740 | 741 | /** 742 | * Returns an editor for this snapshot's entry, or null if either the 743 | * entry has changed since this snapshot was created or if another edit 744 | * is in progress. 745 | */ 746 | public Editor edit() throws IOException { 747 | return DiskLruCache.this.edit(key, sequenceNumber); 748 | } 749 | 750 | /** 751 | * Returns the unbuffered stream with the value for {@code index}. 752 | */ 753 | public InputStream getInputStream(int index) { 754 | return ins[index]; 755 | } 756 | 757 | /** 758 | * Returns the string value for {@code index}. 759 | */ 760 | public String getString(int index) throws IOException { 761 | return inputStreamToString(getInputStream(index)); 762 | } 763 | 764 | @Override public void close() { 765 | for (InputStream in : ins) { 766 | closeQuietly(in); 767 | } 768 | } 769 | } 770 | 771 | /** 772 | * Edits the values for an entry. 773 | */ 774 | public final class Editor { 775 | private final Entry entry; 776 | private boolean hasErrors; 777 | 778 | private Editor(Entry entry) { 779 | this.entry = entry; 780 | } 781 | 782 | /** 783 | * Returns an unbuffered input stream to read the last committed value, 784 | * or null if no value has been committed. 785 | */ 786 | public InputStream newInputStream(int index) throws IOException { 787 | synchronized (DiskLruCache.this) { 788 | if (entry.currentEditor != this) { 789 | throw new IllegalStateException(); 790 | } 791 | if (!entry.readable) { 792 | return null; 793 | } 794 | return new FileInputStream(entry.getCleanFile(index)); 795 | } 796 | } 797 | 798 | /** 799 | * Returns the last committed value as a string, or null if no value 800 | * has been committed. 801 | */ 802 | public String getString(int index) throws IOException { 803 | InputStream in = newInputStream(index); 804 | return in != null ? inputStreamToString(in) : null; 805 | } 806 | 807 | /** 808 | * Returns a new unbuffered output stream to write the value at 809 | * {@code index}. If the underlying output stream encounters errors 810 | * when writing to the filesystem, this edit will be aborted when 811 | * {@link #commit} is called. The returned output stream does not throw 812 | * IOExceptions. 813 | */ 814 | public OutputStream newOutputStream(int index) throws IOException { 815 | synchronized (DiskLruCache.this) { 816 | if (entry.currentEditor != this) { 817 | throw new IllegalStateException(); 818 | } 819 | return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); 820 | } 821 | } 822 | 823 | /** 824 | * Sets the value at {@code index} to {@code value}. 825 | */ 826 | public void set(int index, String value) throws IOException { 827 | Writer writer = null; 828 | try { 829 | writer = new OutputStreamWriter(newOutputStream(index), UTF_8); 830 | writer.write(value); 831 | } finally { 832 | closeQuietly(writer); 833 | } 834 | } 835 | 836 | /** 837 | * Commits this edit so it is visible to readers. This releases the 838 | * edit lock so another edit may be started on the same key. 839 | */ 840 | public void commit() throws IOException { 841 | if (hasErrors) { 842 | completeEdit(this, false); 843 | remove(entry.key); // the previous entry is stale 844 | } else { 845 | completeEdit(this, true); 846 | } 847 | } 848 | 849 | /** 850 | * Aborts this edit. This releases the edit lock so another edit may be 851 | * started on the same key. 852 | */ 853 | public void abort() throws IOException { 854 | completeEdit(this, false); 855 | } 856 | 857 | private class FaultHidingOutputStream extends FilterOutputStream { 858 | private FaultHidingOutputStream(OutputStream out) { 859 | super(out); 860 | } 861 | 862 | @Override public void write(int oneByte) { 863 | try { 864 | out.write(oneByte); 865 | } catch (IOException e) { 866 | hasErrors = true; 867 | } 868 | } 869 | 870 | @Override public void write(byte[] buffer, int offset, int length) { 871 | try { 872 | out.write(buffer, offset, length); 873 | } catch (IOException e) { 874 | hasErrors = true; 875 | } 876 | } 877 | 878 | @Override public void close() { 879 | try { 880 | out.close(); 881 | } catch (IOException e) { 882 | hasErrors = true; 883 | } 884 | } 885 | 886 | @Override public void flush() { 887 | try { 888 | out.flush(); 889 | } catch (IOException e) { 890 | hasErrors = true; 891 | } 892 | } 893 | } 894 | } 895 | 896 | private final class Entry { 897 | private final String key; 898 | 899 | /** Lengths of this entry's files. */ 900 | private final long[] lengths; 901 | 902 | /** True if this entry has ever been published */ 903 | private boolean readable; 904 | 905 | /** The ongoing edit or null if this entry is not being edited. */ 906 | private Editor currentEditor; 907 | 908 | /** The sequence number of the most recently committed edit to this entry. */ 909 | private long sequenceNumber; 910 | 911 | private Entry(String key) { 912 | this.key = key; 913 | this.lengths = new long[valueCount]; 914 | } 915 | 916 | public String getLengths() throws IOException { 917 | StringBuilder result = new StringBuilder(); 918 | for (long size : lengths) { 919 | result.append(' ').append(size); 920 | } 921 | return result.toString(); 922 | } 923 | 924 | /** 925 | * Set lengths using decimal numbers like "10123". 926 | */ 927 | private void setLengths(String[] strings) throws IOException { 928 | if (strings.length != valueCount) { 929 | throw invalidLengths(strings); 930 | } 931 | 932 | try { 933 | for (int i = 0; i < strings.length; i++) { 934 | lengths[i] = Long.parseLong(strings[i]); 935 | } 936 | } catch (NumberFormatException e) { 937 | throw invalidLengths(strings); 938 | } 939 | } 940 | 941 | private IOException invalidLengths(String[] strings) throws IOException { 942 | throw new IOException("unexpected journal line: " + Arrays.toString(strings)); 943 | } 944 | 945 | public File getCleanFile(int i) { 946 | return new File(directory, key + "." + i); 947 | } 948 | 949 | public File getDirtyFile(int i) { 950 | return new File(directory, key + "." + i + ".tmp"); 951 | } 952 | } 953 | } 954 | -------------------------------------------------------------------------------- /library/src/main/java/com/yjx/sharelibrary/Share.java: -------------------------------------------------------------------------------- 1 | package com.yjx.sharelibrary;/** 2 | * Created by yjx on 15/5/22. 3 | */ 4 | 5 | import android.graphics.Bitmap; 6 | import android.os.AsyncTask; 7 | 8 | import com.yjx.sharelibrary.cache.DiskCache; 9 | import com.yjx.sharelibrary.cache.MemoryCache; 10 | 11 | /** 12 | * User: YJX 13 | * Date: 2015-05-22 14 | * Time: 15:08 15 | * 主体类 16 | */ 17 | public final class Share { 18 | //名字 19 | private static String shareName; 20 | //缓存大小 21 | private static int cacheSize; 22 | private static DiskCache diskCache = null; 23 | private static MemoryCache memoryCache = null; 24 | 25 | 26 | /** 27 | * 初始化 28 | */ 29 | public static void init(String shareName, int cacheSize, String path) { 30 | Share.shareName = shareName; 31 | Share.cacheSize = cacheSize; 32 | 33 | Share.memoryCache = new MemoryCache(); 34 | Share.diskCache = new DiskCache(cacheSize, path, 1); 35 | 36 | } 37 | 38 | /** 39 | * 设置int类型的值 40 | * 41 | * @param key 键 42 | * @param value 值 43 | */ 44 | public static void putInt(String key, int value) { 45 | Share.memoryCache.put(key, new Integer(value)); 46 | Share.diskCache.put(key, new Integer(value)); 47 | 48 | } 49 | 50 | /** 51 | * 设置long类型的值 52 | * 53 | * @param key 键 54 | * @param value 值 55 | */ 56 | public static void putLong(String key, long value) { 57 | Share.memoryCache.put(key, new Long(value)); 58 | Share.diskCache.put(key, new Long(value)); 59 | } 60 | 61 | /** 62 | * 设置boolean类型的值 63 | * 64 | * @param key 键 65 | * @param value 值 66 | */ 67 | public static void putBoolean(String key, boolean value) { 68 | Share.memoryCache.put(key, new Boolean(value)); 69 | Share.diskCache.put(key, new Boolean(value)); 70 | } 71 | 72 | 73 | /** 74 | * 设置String类型的值 75 | * 76 | * @param key 键 77 | * @param value 值 78 | */ 79 | public static void putString(String key, String value) { 80 | Share.memoryCache.put(key, value); 81 | Share.diskCache.put(key, value); 82 | } 83 | 84 | /** 85 | * 设置float类型的值 86 | * 87 | * @param key 键 88 | * @param value 值 89 | */ 90 | public static void putFloat(String key, float value) { 91 | Share.memoryCache.put(key, new Float(value)); 92 | Share.diskCache.put(key, new Float(value)); 93 | } 94 | 95 | /** 96 | * 设置double类型的值 97 | * 98 | * @param key 键 99 | * @param value 值 100 | */ 101 | public static void putDouble(String key, double value) { 102 | Share.memoryCache.put(key, new Double(value)); 103 | Share.diskCache.put(key, new Double(value)); 104 | } 105 | 106 | /** 107 | * 设置Object类型的值 108 | * 109 | * @param key 键 110 | * @param value 值 111 | */ 112 | public static void putObject(String key, Object value) { 113 | Share.memoryCache.put(key, value); 114 | Share.diskCache.put(key, value); 115 | 116 | } 117 | 118 | /** 119 | * 设置bytes类型的值 120 | * 121 | * @param key 键 122 | * @param bytes 值 123 | */ 124 | public static void putBytes(String key, byte[] bytes) { 125 | Share.memoryCache.put(key, bytes); 126 | Share.diskCache.put(key, bytes); 127 | 128 | } 129 | 130 | /** 131 | * 设置Bitmap类型的值 132 | * 133 | * @param key 键 134 | * @param value 值 135 | */ 136 | public static void putBitmap(String key, Bitmap value) { 137 | Share.memoryCache.put(key, value); 138 | Share.diskCache.put(key, value); 139 | 140 | } 141 | 142 | 143 | /** 144 | * 得到int类型的值 145 | * 146 | * @param key 键 147 | * @param defalut 默认值 148 | * @return int值 149 | */ 150 | public static int getInt(String key, int defalut) { 151 | Integer value = memoryCache.getInt(key); 152 | if (value == null) { 153 | value = diskCache.getInt(key); 154 | 155 | if (value == null) { 156 | return defalut; 157 | } else { 158 | memoryCache.put(key,value); 159 | return value.intValue(); 160 | } 161 | } else { 162 | return value.intValue(); 163 | } 164 | 165 | } 166 | 167 | /** 168 | * 得到long类型的值 169 | * 170 | * @param key 键 171 | * @param defalut 默认值 172 | * @return long值 173 | */ 174 | public static long getLong(String key, long defalut) { 175 | Long value = memoryCache.getLong(key); 176 | if (value == null) { 177 | value = diskCache.getLong(key); 178 | 179 | if (value != null) { 180 | memoryCache.put(key,value); 181 | return value.longValue(); 182 | } 183 | else 184 | return defalut; 185 | } else { 186 | return value.longValue(); 187 | } 188 | } 189 | 190 | /** 191 | * 得到String类型的值 192 | * 193 | * @param key 键 194 | * @return String值 195 | */ 196 | public static String getString(String key) { 197 | String value = memoryCache.getString(key); 198 | if (value == null) { 199 | value = diskCache.getString(key); 200 | if (value!=null) 201 | memoryCache.put(key,value); 202 | return value; 203 | } else { 204 | return value; 205 | } 206 | } 207 | 208 | /** 209 | * 得到boolean类型的值 210 | * 211 | * @param key 键 212 | * @param defalut 默认值 213 | * @return boolean值 214 | */ 215 | public static boolean getBoolean(String key, boolean defalut) { 216 | Boolean value = memoryCache.getBoolean(key); 217 | if (value == null) { 218 | value = diskCache.getBoolean(key); 219 | if (value == null) 220 | return defalut; 221 | memoryCache.put(key,value); 222 | return value.booleanValue(); 223 | } else { 224 | return value.booleanValue(); 225 | } 226 | } 227 | 228 | /** 229 | * 得到double类型的值 230 | * 231 | * @param key 键 232 | * @param defalut 默认值 233 | * @return double值 234 | */ 235 | public static double getDouble(String key, double defalut) { 236 | Double value = memoryCache.getDouble(key); 237 | if (value == null) { 238 | value = diskCache.getDouble(key); 239 | 240 | if (value == null) 241 | return defalut; 242 | memoryCache.put(key,value); 243 | return value.doubleValue(); 244 | } else { 245 | return value.doubleValue(); 246 | } 247 | } 248 | 249 | /** 250 | * 得到float类型的值 251 | * 252 | * @param key 键 253 | * @param defalut 默认值 254 | * @return float值 255 | */ 256 | public static float getFloat(String key, float defalut) { 257 | Float value = memoryCache.getFloat(key); 258 | if (value == null) { 259 | value = diskCache.getFloat(key); 260 | if (value == null) 261 | return defalut; 262 | memoryCache.put(key,value); 263 | return value.floatValue(); 264 | } else { 265 | return value.floatValue(); 266 | } 267 | } 268 | 269 | /** 270 | * 得到object类型的值 271 | * 272 | * @param key 键 273 | * @return object值 274 | */ 275 | public static Object getObject(String key) { 276 | Object object = memoryCache.getObject(key); 277 | if (object == null) { 278 | object = diskCache.getObject(key); 279 | if (object!=null) 280 | memoryCache.put(key,object); 281 | return object; 282 | } else { 283 | return object; 284 | } 285 | } 286 | 287 | /** 288 | * 得到bytes类型的值 289 | * 290 | * @param key 键 291 | * @return bytes值 292 | */ 293 | 294 | public static byte[] getBytes(String key) { 295 | byte[] bytes = memoryCache.getBytes(key); 296 | if (bytes == null) { 297 | bytes = diskCache.getBytes(key); 298 | } 299 | if (bytes!=null) 300 | memoryCache.put(key,bytes); 301 | return bytes; 302 | } 303 | 304 | /** 305 | * 得到Bitmap类型的值 306 | * 307 | * @param key 键 308 | * @return bitmap值 309 | */ 310 | public static Bitmap getBitmap(String key) { 311 | Bitmap bitmap = memoryCache.getBitmap(key); 312 | if (bitmap == null) { 313 | bitmap = diskCache.getBitmap(key); 314 | 315 | } 316 | if (bitmap!=null) 317 | memoryCache.put(key,bitmap); 318 | 319 | return bitmap; 320 | } 321 | 322 | 323 | /** 324 | * 清楚数据 325 | */ 326 | public static void clearData() { 327 | Share.memoryCache.clear(); 328 | Share.diskCache.clear(); 329 | 330 | } 331 | 332 | /** 333 | * 清除指定的数据 334 | * 335 | * @param key 键 336 | */ 337 | public static void remove(String key) { 338 | Share.diskCache.remove(key); 339 | 340 | Share.memoryCache.remove(key); 341 | } 342 | 343 | 344 | //异步方法 345 | 346 | /** 347 | * 异步设置Bitmap类型的值 348 | * 349 | * @param key 键 350 | * @param value 值 351 | * @param callback 回调函数 352 | */ 353 | public static void putBitmapAsync(final String key, final Bitmap value, final Callback callback) { 354 | new AsyncTask() { 355 | @Override 356 | protected Boolean doInBackground(Void... params) { 357 | putBitmap(key, value); 358 | return true; 359 | } 360 | 361 | @Override 362 | protected void onPostExecute(Boolean success) { 363 | super.onPreExecute(); 364 | if (callback != null) { 365 | callback.apply(); 366 | } 367 | } 368 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 369 | } 370 | 371 | /** 372 | * 异步设置String类型的值 373 | * 374 | * @param key 键 375 | * @param value 值 376 | * @param callback 回调函数 377 | */ 378 | public static void putStringAsync(final String key, final String value, final Callback callback) { 379 | new AsyncTask() { 380 | @Override 381 | protected Boolean doInBackground(Void... params) { 382 | putString(key, value); 383 | return true; 384 | } 385 | 386 | @Override 387 | protected void onPostExecute(Boolean success) { 388 | super.onPreExecute(); 389 | if (callback != null) { 390 | callback.apply(); 391 | } 392 | } 393 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 394 | 395 | } 396 | 397 | /** 398 | * 异步设置Object类型的值 399 | * 400 | * @param key 键 401 | * @param value 值 402 | * @param callback 回调函数 403 | */ 404 | public static void putObjectAsync(final String key, final Object value, final Callback callback) { 405 | new AsyncTask() { 406 | @Override 407 | protected Boolean doInBackground(Void... params) { 408 | putObject(key, value); 409 | return true; 410 | } 411 | 412 | @Override 413 | protected void onPostExecute(Boolean success) { 414 | super.onPreExecute(); 415 | if (callback != null) { 416 | callback.apply(); 417 | } 418 | } 419 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 420 | 421 | } 422 | 423 | /** 424 | * 异步设置long类型的值 425 | * 426 | * @param key 键 427 | * @param value 值 428 | * @param callback 回调函数 429 | */ 430 | public static void putLongAsync(final String key, final long value, final Callback callback) { 431 | new AsyncTask() { 432 | @Override 433 | protected Boolean doInBackground(Void... params) { 434 | putLong(key, value); 435 | return true; 436 | } 437 | 438 | @Override 439 | protected void onPostExecute(Boolean success) { 440 | super.onPreExecute(); 441 | if (callback != null) { 442 | callback.apply(); 443 | } 444 | } 445 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 446 | } 447 | 448 | /** 449 | * 异步设置int类型的值 450 | * 451 | * @param key 键 452 | * @param value 值 453 | * @param callback 回调函数 454 | */ 455 | public static void putIntAsync(final String key, final int value, final Callback callback) { 456 | 457 | new AsyncTask() { 458 | @Override 459 | protected Boolean doInBackground(Void... params) { 460 | putInt(key, value); 461 | return true; 462 | } 463 | 464 | @Override 465 | protected void onPostExecute(Boolean success) { 466 | super.onPreExecute(); 467 | if (callback != null) { 468 | callback.apply(); 469 | } 470 | } 471 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 472 | } 473 | 474 | 475 | /** 476 | * 异步设置double类型的值 477 | * 478 | * @param key 键 479 | * @param value 值 480 | * @param callback 回调函数 481 | */ 482 | public static void putDoubleAsync(final String key, final double value, final Callback callback) { 483 | new AsyncTask() { 484 | @Override 485 | protected Boolean doInBackground(Void... params) { 486 | putDouble(key, value); 487 | return true; 488 | } 489 | 490 | @Override 491 | protected void onPostExecute(Boolean success) { 492 | super.onPreExecute(); 493 | if (callback != null) { 494 | callback.apply(); 495 | } 496 | } 497 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 498 | } 499 | 500 | /** 501 | * 异步设置float类型的值 502 | * 503 | * @param key 键 504 | * @param value 值 505 | * @param callback 回调函数 506 | */ 507 | public static void putFloatAsync(final String key, final float value, final Callback callback) { 508 | new AsyncTask() { 509 | @Override 510 | protected Boolean doInBackground(Void... params) { 511 | putFloat(key, value); 512 | return true; 513 | } 514 | 515 | @Override 516 | protected void onPostExecute(Boolean success) { 517 | super.onPreExecute(); 518 | if (callback != null) { 519 | callback.apply(); 520 | } 521 | } 522 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 523 | } 524 | 525 | /** 526 | * 异步设置byte[]类型的值 527 | * 528 | * @param key 键 529 | * @param value 值 530 | * @param callback 回调函数 531 | */ 532 | public static void putBytesAsync(final String key, final byte[] value, final Callback callback) { 533 | new AsyncTask() { 534 | @Override 535 | protected Boolean doInBackground(Void... params) { 536 | putBytes(key, value); 537 | return true; 538 | } 539 | 540 | @Override 541 | protected void onPostExecute(Boolean success) { 542 | super.onPreExecute(); 543 | if (callback != null) { 544 | callback.apply(); 545 | } 546 | } 547 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 548 | } 549 | 550 | /** 551 | * 异步设置boolean类型的值 552 | * 553 | * @param key 键 554 | * @param value 值 555 | * @param callback 回调函数 556 | */ 557 | public static void putBooleanAsync(final String key, final boolean value, final Callback callback) { 558 | new AsyncTask() { 559 | @Override 560 | protected Boolean doInBackground(Void... params) { 561 | putBoolean(key, value); 562 | return true; 563 | } 564 | 565 | @Override 566 | protected void onPostExecute(Boolean success) { 567 | super.onPreExecute(); 568 | if (callback != null) { 569 | 570 | callback.apply(); 571 | } 572 | } 573 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 574 | } 575 | 576 | /** 577 | * 回调接口 578 | */ 579 | public interface Callback { 580 | void apply(); 581 | } 582 | 583 | 584 | } 585 | -------------------------------------------------------------------------------- /library/src/main/java/com/yjx/sharelibrary/cache/Cache.java: -------------------------------------------------------------------------------- 1 | package com.yjx.sharelibrary.cache; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * Created by yjx on 15/5/22. 7 | * 缓存接口 8 | */ 9 | public interface Cache { 10 | 11 | Bitmap getBitmap(String key); 12 | 13 | Object getString(String key); 14 | 15 | byte[] getBytes(String key); 16 | 17 | Object getObject(String key); 18 | 19 | Integer getInt(String key); 20 | 21 | Long getLong(String key); 22 | 23 | Double getDouble(String key); 24 | 25 | Float getFloat(String key); 26 | 27 | Boolean getBoolean(String key); 28 | 29 | 30 | void put(String key, Object value); 31 | 32 | void remove(String key); 33 | 34 | void clear(); 35 | } 36 | -------------------------------------------------------------------------------- /library/src/main/java/com/yjx/sharelibrary/cache/DiskCache.java: -------------------------------------------------------------------------------- 1 | package com.yjx.sharelibrary.cache; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | 6 | import com.yjx.sharelibrary.DiskLruCache; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.ObjectInputStream; 13 | import java.io.ObjectOutputStream; 14 | import java.io.OutputStream; 15 | 16 | /** 17 | * User: YJX 18 | * Date: 2015-05-22 19 | * Time: 15:30 20 | * 硬盘缓存 21 | */ 22 | public class DiskCache implements Cache { 23 | private DiskLruCache diskLruCache; 24 | private int cacheSize;//缓存大小 25 | private String path;//缓存路径 26 | private int version;//版本号 27 | 28 | public DiskCache(int cacheSize, String path, int version) { 29 | this.cacheSize = cacheSize; 30 | this.path = path; 31 | this.version = version; 32 | try { 33 | this.diskLruCache = DiskLruCache.open(new File(path), version, 1, cacheSize); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | 40 | @Override 41 | public Bitmap getBitmap(String key) { 42 | byte[] bytes = getBytes(key); 43 | if (bytes != null) { 44 | return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 45 | } 46 | return null; 47 | } 48 | 49 | @Override 50 | public String getString(String key) { 51 | byte[] bytes = getBytes(key); 52 | if (bytes != null) { 53 | return new String(bytes); 54 | } 55 | return null; 56 | } 57 | 58 | @Override 59 | public byte[] getBytes(String key) { 60 | try { 61 | DiskLruCache.Snapshot snapshot = this.diskLruCache.get(key); 62 | if (snapshot != null && snapshot.getInputStream(0) != null) 63 | return write(this.diskLruCache.get(key).getInputStream(0)); 64 | else 65 | return null; 66 | } catch (IOException e) { 67 | e.printStackTrace(); 68 | return null; 69 | } 70 | } 71 | 72 | @Override 73 | public Object getObject(String key) { 74 | try { 75 | DiskLruCache.Snapshot snapshot = this.diskLruCache.get(key); 76 | if (snapshot != null && snapshot.getInputStream(0) != null) { 77 | ObjectInputStream objectInputStream = new ObjectInputStream(this.diskLruCache.get(key).getInputStream(0)); 78 | return objectInputStream.readObject(); 79 | } else { 80 | return null; 81 | } 82 | } catch (Exception e) { 83 | return null; 84 | } 85 | } 86 | 87 | @Override 88 | public Integer getInt(String key) { 89 | Object obj = getObject(key); 90 | if (obj != null) 91 | return ((Integer) obj); 92 | return null; 93 | } 94 | 95 | @Override 96 | public Long getLong(String key) { 97 | 98 | Object obj = getObject(key); 99 | if (obj != null) 100 | return ((Long) obj); 101 | return null; 102 | } 103 | 104 | @Override 105 | public Double getDouble(String key) { 106 | Object obj = getObject(key); 107 | if (obj != null) 108 | return ((Double) obj); 109 | return null; 110 | } 111 | 112 | @Override 113 | public Float getFloat(String key) { 114 | Object obj = getObject(key); 115 | if (obj != null) 116 | return ((Float) obj); 117 | return null; 118 | } 119 | 120 | @Override 121 | public Boolean getBoolean(String key) { 122 | Object obj = getObject(key); 123 | if (obj != null) 124 | return ((Boolean) obj); 125 | return null; 126 | } 127 | 128 | @Override 129 | public void put(String key, Object value) { 130 | try { 131 | DiskLruCache.Editor editor = this.diskLruCache.edit(key); 132 | OutputStream outputStream = editor.newOutputStream(0); 133 | if (value instanceof Bitmap) { 134 | Bitmap bitmap = (Bitmap) value; 135 | outputStream.write(Bitmap2Bytes(bitmap)); 136 | outputStream.close(); 137 | } else if (value instanceof String) { 138 | outputStream.write(((String) value).getBytes()); 139 | outputStream.close(); 140 | } else { 141 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); 142 | objectOutputStream.writeObject(value); 143 | outputStream.close(); 144 | objectOutputStream.close(); 145 | 146 | } 147 | editor.commit(); 148 | this.diskLruCache.flush(); 149 | 150 | } catch (Exception e) { 151 | e.printStackTrace(); 152 | } 153 | 154 | 155 | } 156 | 157 | @Override 158 | public void remove(String key) { 159 | try { 160 | this.diskLruCache.remove(key); 161 | } catch (IOException e) { 162 | e.printStackTrace(); 163 | } 164 | } 165 | 166 | @Override 167 | public void clear() { 168 | File file = new File(path); 169 | if (file.exists()) { 170 | File[] files = file.listFiles(); 171 | for (File f : files) { 172 | f.delete(); 173 | } 174 | } 175 | } 176 | 177 | //写入数据 178 | private void write(OutputStream out, InputStream in) { 179 | int len = 0; 180 | byte[] bytes = new byte[1024]; 181 | try { 182 | while ((len = in.read(bytes, 0, bytes.length)) != -1) { 183 | out.write(bytes, 0, len); 184 | } 185 | in.close(); 186 | out.close(); 187 | } catch (IOException e) { 188 | e.printStackTrace(); 189 | } 190 | } 191 | 192 | private byte[] write(InputStream in) { 193 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 194 | int len = 0; 195 | byte[] bytes = new byte[1024]; 196 | try { 197 | while ((len = in.read(bytes, 0, bytes.length)) != -1) { 198 | out.write(bytes, 0, len); 199 | } 200 | in.close(); 201 | out.close(); 202 | } catch (IOException e) { 203 | e.printStackTrace(); 204 | } 205 | return out.toByteArray(); 206 | } 207 | private byte[] Bitmap2Bytes(Bitmap bm) { 208 | ByteArrayOutputStream baos =new ByteArrayOutputStream(); 209 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 210 | try { 211 | baos.flush(); 212 | baos.close(); 213 | if (!bm.isRecycled()){ 214 | bm.recycle(); 215 | } 216 | } catch (IOException e) { 217 | e.printStackTrace(); 218 | } 219 | return baos.toByteArray(); 220 | } 221 | 222 | 223 | } 224 | -------------------------------------------------------------------------------- /library/src/main/java/com/yjx/sharelibrary/cache/MemoryCache.java: -------------------------------------------------------------------------------- 1 | package com.yjx.sharelibrary.cache;/** 2 | * Created by yjx on 15/5/22. 3 | */ 4 | 5 | import android.graphics.Bitmap; 6 | 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.ConcurrentMap; 9 | 10 | /** 11 | * User: YJX 12 | * Date: 2015-05-22 13 | * Time: 15:09 14 | * 内存缓存 15 | */ 16 | public class MemoryCache implements Cache { 17 | private ConcurrentMap hashMap; 18 | 19 | public MemoryCache() { 20 | hashMap = new ConcurrentHashMap(); 21 | } 22 | 23 | 24 | @Override 25 | public Bitmap getBitmap(String key) { 26 | return (Bitmap) this.hashMap.get(key); 27 | } 28 | 29 | @Override 30 | public String getString(String key) { 31 | if (hashMap.containsKey(key)) 32 | return String.valueOf(this.hashMap.get(key)); 33 | return null; 34 | } 35 | 36 | @Override 37 | public byte[] getBytes(String key) { 38 | if (hashMap.containsKey(key)) 39 | return (byte[]) this.hashMap.get(key); 40 | return null; 41 | } 42 | 43 | @Override 44 | public Object getObject(String key) { 45 | if (hashMap.containsKey(key)) 46 | return this.hashMap.get(key); 47 | return null; 48 | } 49 | 50 | @Override 51 | public Integer getInt(String key) { 52 | if (hashMap.containsKey(key)) { 53 | Integer value = (Integer) this.hashMap.get(key); 54 | return value; 55 | } else { 56 | return null; 57 | } 58 | } 59 | 60 | @Override 61 | public Long getLong(String key) { 62 | if (hashMap.containsKey(key)) { 63 | Long value = (Long) this.hashMap.get(key); 64 | return value; 65 | } else { 66 | return null; 67 | } 68 | } 69 | 70 | @Override 71 | public Double getDouble(String key) { 72 | if (hashMap.containsKey(key)) { 73 | Double value = (Double) this.hashMap.get(key); 74 | return value; 75 | } else { 76 | return null; 77 | } 78 | 79 | } 80 | 81 | @Override 82 | public Float getFloat(String key) { 83 | if (hashMap.containsKey(key)) { 84 | Float value = (Float) this.hashMap.get(key); 85 | return value; 86 | } else { 87 | return null; 88 | } 89 | } 90 | 91 | @Override 92 | public Boolean getBoolean(String key) { 93 | if (hashMap.containsKey(key)) { 94 | Boolean value = (Boolean) this.hashMap.get(key); 95 | return value; 96 | } else { 97 | return null; 98 | } 99 | } 100 | 101 | 102 | @Override 103 | public void put(String key, Object value) { 104 | if (value instanceof Bitmap || value instanceof String) 105 | this.hashMap.put(key, value); 106 | else if (value instanceof Integer) { 107 | this.hashMap.put(key, new Integer((int) value)); 108 | } else if (value instanceof Long) { 109 | this.hashMap.put(key, new Long((long) value)); 110 | } else if (value instanceof Double) { 111 | this.hashMap.put(key, new Double((double) value)); 112 | } else if (value instanceof Float) { 113 | this.hashMap.put(key, new Float((float) value)); 114 | } else if (value instanceof Boolean) { 115 | this.hashMap.put(key, new Boolean((boolean) value)); 116 | } else 117 | this.hashMap.put(key, value); 118 | } 119 | 120 | @Override 121 | public void remove(String key) { 122 | if (hashMap.containsKey(key)) 123 | this.hashMap.remove(key); 124 | } 125 | 126 | @Override 127 | public void clear() { 128 | hashMap.clear(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ShareLibrary 3 | 4 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | --------------------------------------------------------------------------------