├── .gitignore ├── .idea ├── compiler.xml └── misc.xml ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── spholder │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── spholder │ │ │ ├── MainActivity.kt │ │ │ ├── bo │ │ │ ├── DailyReward.kt │ │ │ ├── Game.kt │ │ │ └── Time.kt │ │ │ ├── daily │ │ │ ├── ObjectTest.kt │ │ │ ├── TaskOneController.kt │ │ │ ├── TestActivity.kt │ │ │ └── util │ │ │ │ └── DataUtil.kt │ │ │ ├── proxy │ │ │ ├── JavaSP.java │ │ │ ├── SpConfig.java │ │ │ └── SpRetrofit.java │ │ │ └── test │ │ │ ├── TestCase.kt │ │ │ ├── TestMMKV.kt │ │ │ └── TestSP.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_test.xml │ │ └── task_item_one.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 │ │ ├── task1_go.png │ │ └── task1_goed.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── spholder │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── doc ├── CHANGELOG.md └── tech-design.md ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── preferences-core ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── forjrking │ │ └── preferences │ │ ├── PreferencesOwner.kt │ │ ├── bindings │ │ ├── Clearable.kt │ │ └── PreferenceFieldBinder.kt │ │ ├── cache │ │ ├── AtomicCache.kt │ │ └── Cache.kt │ │ ├── extensions │ │ ├── EditorExtKt.kt │ │ └── TypeExtKt.kt │ │ ├── provide │ │ ├── MultiProcessSharedPreferences.kt │ │ ├── ProvideKt.kt │ │ └── QueuedWork.kt │ │ └── serialize │ │ └── Serializer.kt │ └── test │ └── java │ └── com │ └── forjrking │ └── preferences │ ├── ExampleUnitTest.kt │ ├── cache │ └── AtomicCacheTest.kt │ └── extensions │ └── EditorExtKtKtTest.kt ├── preferences-gson ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── forjrking │ │ └── preferences │ │ └── serialize │ │ └── GsonSerializer.kt │ └── test │ └── java │ └── com │ └── forjrking │ └── preferences │ └── ExampleUnitTest.kt ├── preferences-ktx ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── forjrking │ │ └── preferences │ │ └── ktx │ │ └── PreferencesKt.kt │ └── test │ └── java │ └── com │ └── forjrking │ └── preferences │ └── ExampleUnitTest.kt └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .cxx 9 | ### Android template 10 | # Built application files 11 | *.apk 12 | *.aar 13 | *.ap_ 14 | *.aab 15 | 16 | # Files for the ART/Dalvik VM 17 | *.dex 18 | 19 | # Java class files 20 | *.class 21 | 22 | # Generated files 23 | bin/ 24 | gen/ 25 | out/ 26 | # Uncomment the following line in case you need and you don't have the release build type files in your app 27 | # release/ 28 | 29 | # Gradle files 30 | .gradle/ 31 | build/ 32 | 33 | # Local configuration file (sdk path, etc) 34 | local.properties 35 | 36 | # Proguard folder generated by Eclipse 37 | proguard/ 38 | 39 | # Log Files 40 | *.log 41 | 42 | # Android Studio Navigation editor temp files 43 | .navigation/ 44 | 45 | # Android Studio captures folder 46 | captures/ 47 | 48 | # IntelliJ 49 | *.iml 50 | .idea/workspace.xml 51 | .idea/tasks.xml 52 | .idea/gradle.xml 53 | .idea/assetWizardSettings.xml 54 | .idea/dictionaries 55 | .idea/libraries 56 | # Android Studio 3 in .gitignore file. 57 | .idea/caches 58 | .idea/modules.xml 59 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 60 | .idea/navEditor.xml 61 | 62 | # Keystore files 63 | # Uncomment the following lines if you do not want to check your keystore files in. 64 | #*.jks 65 | #*.keystore 66 | 67 | # External native build folder generated in Android Studio 2.2 and later 68 | .externalNativeBuild 69 | .cxx/ 70 | 71 | # Google Services (e.g. APIs or Firebase) 72 | # google-services.json 73 | 74 | # Freeline 75 | freeline.py 76 | freeline/ 77 | freeline_project_description.json 78 | 79 | # fastlane 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots 83 | fastlane/test_output 84 | fastlane/readme.md 85 | 86 | # Version control 87 | vcs.xml 88 | 89 | # lint 90 | lint/intermediates/ 91 | lint/generated/ 92 | lint/outputs/ 93 | lint/tmp/ 94 | # lint/reports/ 95 | 96 | /.idea/ 97 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 32 | 33 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Preference-ktx [![](https://jitpack.io/v/forJrking/Preferences.svg)](https://jitpack.io/#forJrking/Preferences) 2 | 3 | ### 简介 4 | 5 | > `Preferences` 基于Kotlin委托实现了`SharedPreferences`支持多进程、数据加解密、MMKV,另外对原生`SharedPreferences`进行Hook优化降低ANR,缓存优化。 6 | 7 | ### 特点 8 | - 支持多进程 9 | - 支持MMKV无缝接入 10 | - 支持sp和mmkv的getAll方法 11 | - 支持数据加解密(基于androidx.security) 12 | 13 | ### 项目github地址 14 | 15 | https://github.com/forJrking/Preferences 请start表示对我的支持哦! 16 | 17 | ### Preferences 18 | 19 | 1. 添加依赖 20 | 21 | ```kotlin 22 | repositories { 23 | ... 24 | maven { url 'https://jitpack.io' } 25 | } 26 | 27 | dependencies { 28 | implementation 'com.github.forjrking.pref:pref-core:2.0.0' // 必须 29 | implementation 'com.github.forjrking.pref:pref-gson:2.0.0' // 非必须 30 | implementation 'com.github.forjrking.pref:pref-ktx:2.0.0' // 非必须 31 | implementation 'com.google.code.gson:gson:2.8.5' //存储对象需要(非必须) 32 | implementation 'com.tencent:mmkv-static:1.2.1' // mmkv支持加密和多进程(非必须) 33 | implementation 'androidx.security:security-crypto:1.0.0' // sp加密支持(非必须) 34 | } 35 | 36 | // 必须Application 中初始化, 依赖了pref-gson会自动初始化 37 | PreferenceHolder.context = this.context 38 | // 非必须 如果使用MMKV请初始化并且配置相关 39 | MMKV.initialize(this) ... 40 | // 非必须 用于序列化对象和集合等数据,sp不建议存大量数据, 依赖了pref-gson会自动初始化 41 | PreferenceHolder.serializer = GsonSerializer() 42 | ``` 43 | 44 | 2. 写一个object类,必须使用kt 45 | 46 | ```kotlin 47 | object TestSP : PreferencesOwner() { 48 | var value: Long by preferenceBinding(0L) 49 | var objCase: Game? by preferenceNullableBinding() 50 | } 51 | 52 | // 存入sp 53 | TestSP.value = 100 54 | // 读取sp 55 | val value = TestSP.value 56 | println(value) // 0 or 100 57 | // getAll 58 | TestSP.getAll()?.forEach { 59 | Log.d("TAG", "name:${it.key} value:${it.value}") 60 | } 61 | ``` 62 | 63 | 3. 其他api演示 64 | 65 | ```kotlin 66 | /* 67 | * @param name xml名称 默认为实现类类名,为了防止不同类使用相同字段覆盖数据问题 68 | * @param cryptKey 加密密钥 null 表示不用加密 需要api >= 23 69 | * @param isMMKV 是否使用mmkv 默认false 70 | * @param isMultiProcess 是否使用多进程 建议mmkv sp性能很差 默认false 71 | */ 72 | object TestSP : PreferencesOwner("name","cyptKey",isMMKV,isMultiProcess) { 73 | //带默认值 == getString(key,default) 不可赋值 null 74 | var testStr: String by preferenceBinding('default') 75 | 76 | var coin: Long by preferenceBinding(0L) 77 | 78 | var tes: String? by preferenceNullableBinding() //默认值为 null 可以为其赋值 null 79 | 80 | //支持所有sp支持的数据类型 以及 object 需要初始化上一步的 GsonSerializer 81 | var savedGame: Game? by bindToPreferenceFieldNullable() 82 | } 83 | //getValue 读取sp 84 | val str = TestSP.testStr 85 | val coin = TestSP.coin 86 | println(str) //"" or "something" 87 | 88 | //setValue 存入sp 89 | TestSP.testStr = "AX${Random().nextInt(20)}" 90 | TestSP.coin = 100 91 | ``` 92 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("org.jetbrains.kotlin.android") 4 | } 5 | 6 | android { 7 | namespace = "com.example.spholder" 8 | compileSdk = libs.versions.compileSdk.get().toInt() 9 | 10 | defaultConfig { 11 | applicationId = "com.example.spholder" 12 | // minSdk = libs.versions.minSdk.get().toInt() 13 | minSdk = 23 14 | targetSdk = libs.versions.targetSdk.get().toInt() 15 | versionCode = 1 16 | versionName = "1.0" 17 | 18 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 19 | vectorDrawables { 20 | useSupportLibrary = true 21 | } 22 | } 23 | 24 | buildTypes { 25 | release { 26 | isMinifyEnabled = true 27 | proguardFiles( 28 | getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" 29 | ) 30 | signingConfig = signingConfigs.getByName("debug") 31 | } 32 | } 33 | compileOptions { 34 | sourceCompatibility = JavaVersion.VERSION_1_8 35 | targetCompatibility = JavaVersion.VERSION_1_8 36 | } 37 | kotlinOptions { 38 | jvmTarget = "1.8" 39 | } 40 | buildFeatures { 41 | viewBinding = true 42 | } 43 | composeOptions { 44 | kotlinCompilerExtensionVersion = "1.2.0" 45 | } 46 | dependenciesInfo { 47 | // Disables dependency metadata when building APKs. 48 | includeInApk = false 49 | // Disables dependency metadata when building Android App Bundles. 50 | includeInBundle = false 51 | } 52 | } 53 | 54 | tasks.withType { 55 | useJUnitPlatform() 56 | } 57 | 58 | dependencies { 59 | implementation(libs.gson) 60 | implementation(libs.mmkv) 61 | implementation(libs.androidx.core) 62 | implementation(libs.androidx.appcompat) 63 | implementation(libs.androidx.constraintlayout) 64 | implementation(libs.androidx.lifecycle.runtime) 65 | implementation(libs.androidx.security) 66 | debugImplementation(project("path" to ":preferences-core")) 67 | debugImplementation(project("path" to ":preferences-gson")) 68 | debugImplementation(project("path" to ":preferences-ktx")) 69 | releaseImplementation(libs.bundles.pref) 70 | implementation("com.github.forJrking:StartActivity4Rt:1.0.0") 71 | testImplementation(libs.junit5) 72 | testRuntimeOnly(libs.junit.engine) 73 | androidTestImplementation(libs.espresso.core) 74 | androidTestImplementation(libs.androidx.junit) 75 | } -------------------------------------------------------------------------------- /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 | 23 | -dontwarn com.google.errorprone.annotations.Immutable 24 | -dontwarn javax.annotation.concurrent.GuardedBy -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/spholder/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import com.example.spholder.test.TestSP 6 | import com.forjrking.preferences.PreferencesOwner 7 | import java.util.* 8 | import org.junit.Assert.* 9 | import org.junit.Test 10 | import org.junit.runner.RunWith 11 | import kotlin.system.measureTimeMillis 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * See [testing documentation](http://d.android.com/tools/testing). 17 | */ 18 | @RunWith(AndroidJUnit4::class) 19 | class ExampleInstrumentedTest { 20 | @Test 21 | fun useAppContext() { 22 | // Context of the app under test. 23 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 24 | assertEquals("com.example.spholder", appContext.packageName) 25 | } 26 | 27 | 28 | @Test 29 | fun benchmark() { 30 | repeat(3) { 31 | val writeTimeMillis = measureTimeMillis { 32 | repeat(1000) { 33 | val append = "AR:$it" 34 | UTTestSP.stringCache = append 35 | } 36 | } 37 | println("set Time: $writeTimeMillis") 38 | 39 | val readTimeMillis = measureTimeMillis { 40 | repeat(1000) { 41 | val case = UTTestSP.stringCache 42 | val temp = case 43 | } 44 | } 45 | println("get Time: $readTimeMillis") 46 | } 47 | } 48 | 49 | @Test 50 | fun benchmarkForSpNormal() { 51 | TestSP.stringCase = "testStr" 52 | } 53 | } 54 | 55 | object UTTestSP : PreferencesOwner("sp-normal") { 56 | var stringCache: String by preferenceBinding("A", caching = true) 57 | var stringNoCache: String by preferenceBinding("A", caching = false) 58 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/spholder/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.content.SharedPreferences 7 | import android.os.Bundle 8 | import android.util.Log 9 | import android.view.View 10 | import android.widget.AdapterView 11 | import androidx.appcompat.app.AppCompatActivity 12 | import com.example.spholder.daily.TestActivity 13 | import com.example.spholder.databinding.ActivityMainBinding 14 | import com.example.spholder.test.* 15 | import com.forjrking.activity.library.launch4Result 16 | import com.forjrking.preferences.PreferencesOwner 17 | import kotlin.system.measureTimeMillis 18 | 19 | class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener { 20 | 21 | companion object { 22 | private var testCase: TestCase? = null 23 | private var preferencesOwner: PreferencesOwner? = null 24 | fun write() = testCase?.apply { 25 | intCase = 100 26 | longCase = 101L 27 | floatCase = 102F 28 | booleanCase = false 29 | stringCase = "123ABC-:/><;\"!##$%^&*" 30 | objCase = testObj.copy(numberId = 101, datas = null) 31 | setStringCase = setOf("NOT NULL") 32 | setObjCase = setOf(testObj.copy(numberId = 102, datas = null)) 33 | setStringNullableCase = setOf("NULLABLE") 34 | setObjNullableCase = setOf(testObj.copy(numberId = 103, datas = null)) 35 | } 36 | 37 | fun read(): String { 38 | return testCase?.run { 39 | StringBuilder() 40 | .append("intCase:$intCase").appendLine() 41 | .append("floatCase:$floatCase").appendLine() 42 | .append("longCase:$longCase").appendLine() 43 | .append("booleanCase:$booleanCase").appendLine() 44 | .append("stringCase:$stringCase").appendLine() 45 | .append("objCase:$objCase").appendLine() 46 | .append("setStringCase:$setStringCase").appendLine() 47 | .append("setObjCase:$setObjCase").appendLine() 48 | .append("setStringNullableCase:$setStringNullableCase").appendLine() 49 | .append("setObjNullableCase:$setObjNullableCase").appendLine().toString() 50 | } ?: "" 51 | } 52 | } 53 | 54 | @SuppressLint("SetTextI18n") 55 | override fun onCreate(savedInstanceState: Bundle?) { 56 | super.onCreate(savedInstanceState) 57 | val mainBinding = ActivityMainBinding.inflate(layoutInflater) 58 | setContentView(mainBinding.root) 59 | mainBinding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { 60 | override fun onItemSelected( 61 | parent: AdapterView<*>?, 62 | view: View?, 63 | position: Int, 64 | id: Long 65 | ) { 66 | val sp = when (resources.getStringArray(R.array.enum_array)[position]) { 67 | "SP-Normal" -> TestSP 68 | "SP-Crypt" -> TestCryptSP 69 | "SP-Multi" -> TestMultiSP 70 | "MMKV-Normal" -> TestMMKV 71 | "MMKV-Crypt" -> TestCryptMMKV 72 | "MMKV-Multi" -> TestMultiMMKV 73 | else -> TODO("not support") 74 | } 75 | testCase = sp 76 | preferencesOwner = sp 77 | preferencesOwner?.clearCache() 78 | preferencesOwner?.clear() 79 | mainBinding.text.apply { 80 | text = "=======${sp::class.java.name}=======\n" 81 | append(read()) 82 | } 83 | write() 84 | mainBinding.text.apply { 85 | append("========Override========\n") 86 | append(read()) 87 | } 88 | } 89 | 90 | override fun onNothingSelected(parent: AdapterView<*>?) { 91 | 92 | } 93 | } 94 | 95 | mainBinding.processBtn.setOnClickListener { 96 | preferencesOwner?.getAll()?.forEach { 97 | Log.d("MainActivity", "-> name:${it.key} -> value:${it.value}") 98 | } 99 | val intent = Intent(this@MainActivity, TestActivity::class.java) 100 | this.launch4Result(intent, 201) { requestCode, resultCode, data -> 101 | when (resultCode) { 102 | Activity.RESULT_OK -> { 103 | mainBinding.text.text = read() 104 | } 105 | 106 | else -> Unit 107 | } 108 | } 109 | } 110 | mainBinding.benchMarkBtn.setOnClickListener { 111 | /////////////////////////////性能测试/////////////////////// 112 | val writeTimeMillis = measureTimeMillis { 113 | repeat(1000) { 114 | write() 115 | } 116 | } 117 | 118 | val readTimeMillis = measureTimeMillis { 119 | repeat(1000) { 120 | read() 121 | } 122 | } 123 | 124 | mainBinding.text.text = 125 | "writeTimeMillis: $writeTimeMillis \nreadTimeMillis: $readTimeMillis" 126 | preferencesOwner?.getAll()?.forEach { 127 | Log.d("MainActivity", "-> name:${it.key} -> value:${it.value}") 128 | } 129 | } 130 | } 131 | 132 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { 133 | Log.d("MainActivity", "onSharedPreferenceChanged-> name:${key}") 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/spholder/bo/DailyReward.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder.bo 2 | 3 | /** 4 | * @description: 5 | * @author: 岛主 6 | * @date: 2020/7/22 11:43 7 | * @version: 1.0.0 8 | */ 9 | data class DailyReward(var dayIndex: String, var isClmiaed: Boolean) -------------------------------------------------------------------------------- /app/src/main/java/com/example/spholder/bo/Game.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder.bo 2 | 3 | /** 4 | * @description: 5 | * @author: 岛主 6 | * @date: 2020/7/21 20:19 7 | * @version: 1.0.0 8 | */ 9 | data class Game( 10 | var numberId: Int, 11 | val path: String?, 12 | val datas: List? = null 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/example/spholder/bo/Time.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder.bo 2 | 3 | /** 4 | * @description: 5 | * @author: 岛主 6 | * @date: 2020/8/1 15:08 7 | * @version: 1.0.0 8 | */ 9 | data class Time(var id: Int, var time: Long) { 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/spholder/daily/ObjectTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.spholder.daily 2 | 3 | import com.example.spholder.bo.DailyReward 4 | import com.example.spholder.bo.Time 5 | import com.example.spholder.daily.util.DataUtil 6 | import com.forjrking.preferences.PreferencesOwner 7 | import java.text.SimpleDateFormat 8 | import java.util.* 9 | 10 | /** 11 | * @description: 12 | * @author: 岛主 13 | * @date: 2020/8/1 14:57 14 | * @version: 1.0.0 15 | */ 16 | object ObjectTest : PreferencesOwner(null, null, false) { 17 | 18 | private fun day(times: Long = System.currentTimeMillis()): String { 19 | val df = SimpleDateFormat("yyyyMMdd", Locale.US) 20 | return df.format(times) 21 | } 22 | 23 | private val default: MutableList