├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml └── runConfigurations.xml ├── CHANGELOG.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── leavesc │ │ └── hello │ │ └── dokv │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── leavesc │ │ │ └── hello │ │ │ └── dokv │ │ │ ├── MainActivity.java │ │ │ ├── MyApplication.java │ │ │ └── model │ │ │ ├── Book.java │ │ │ ├── CustomKeyUser.java │ │ │ └── User.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── leavesc │ └── hello │ └── dokv │ └── ExampleUnitTest.java ├── build.gradle ├── dokv_annotation ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── leavesc │ └── hello │ └── dokv │ ├── DoKV.java │ ├── IDoKVHolder.java │ └── annotation │ └── DoKV.java ├── dokv_impl ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── leavesc │ │ └── hello │ │ └── dokv_imp │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── leavesc │ │ │ └── hello │ │ │ └── dokv_imp │ │ │ └── MMKVDoKVHolder.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── leavesc │ └── hello │ └── dokv_imp │ └── ExampleUnitTest.java ├── dokv_processor ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── leavesc │ └── hello │ └── dokv_processor │ ├── DoKVProcessor.java │ └── utils │ ├── ElementUtils.java │ └── StringUtils.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### **更新记录** 3 | ### **Change Log** 4 | 5 | 6 | 7 | #### **Version 0.1.8** 8 | 9 | 2018/04/03 10 | 11 | - **IDoKVHolder** 新增 **clear()** 方法用于删除全局的缓存数据,**MMKVDoKVHolder** 增加对应实现 12 | - **DoKV** 注解支持自定义缓存 **Key** 。在之前的版本,**DoKV** 默认以**被注解类的类路径**作为缓存 Key,以此来保证 Key 值的唯一性,但考虑到被注解类在后续开发中可能会被移动到其它包下,从而导致丢失缓存数据,因为在此版本中为注解 DoKV 新增了 Key 属性 13 | 14 | 15 | 16 | #### **Version 0.1.6** 17 | 18 | 2018/03/16 19 | 20 | - 初始版本 21 | - 支持外部自定义**序列化与反序列化**的方案,并提供一个默认的开源实现 **MMKVDoKVHolder** 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### DoKV 2 | 3 | DoKV 是一个小巧而强大的 **Key-Value** 管理框架,其设计初衷是为了解决 Android 平台下各种**繁琐且丑陋**的配置类代码 4 | 5 | **(如果你是从我的博客:[Android APT 实例讲解](https://www.jianshu.com/p/cc8379522c5e) 跳转过来的,那需要切换到 master 分支,对应的是第二次的提交记录)** 6 | 7 | 8 | 9 | ### Download 10 | 11 | ```groovy 12 | dependencies { 13 | implementation 'leavesc.hello:dokv:0.1.8' 14 | annotationProcessor 'leavesc.hello:dokv-compiler:0.1.8' 15 | } 16 | ``` 17 | 18 | 如果不想自定义序列化方案,则可以使用我的另一个开源实现 19 | 20 | ```groovy 21 | dependencies { 22 | implementation 'leavesc.hello:dokv-impl:0.1.8' 23 | } 24 | ``` 25 | 26 | 更新日记:[CHANGELOG](CHANGELOG.md) 27 | 28 | 29 | 30 | ### 一、介绍 31 | 32 | 之所以说小巧,是因为 DoKV 的实现仅依赖于**一个注解、一个接口、四个类**。当然,其实现基础不仅仅如此,还需要 APT 技术的支持,需要依赖于 APT 来自动生成某些中间代码,关于 APT 的知识我在以前的一篇博客中也有所介绍,点击查看:[APT](https://www.jianshu.com/p/cc8379522c5e) 33 | 34 | ![](https://upload-images.jianshu.io/upload_images/2552605-c5119a7ba7544e72.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 35 | 36 | 之所以说强大,是因为通过使用 DoKV 后,你基本是可以抛弃如下类型的代码了 37 | 38 | ```java 39 | SharedPreferences sharedPreferences = getSharedPreferences("SharedPreferencesName", Context.MODE_PRIVATE); 40 | SharedPreferences.Editor editor = sharedPreferences.edit(); 41 | editor.putString("IP", "192.168.0.1"); 42 | editor.commit(); 43 | String userName = sharedPreferences.getString("userName", ""); 44 | String ip = sharedPreferences.getString("IP", ""); 45 | ``` 46 | 47 | 通常,我们的应用都会有很多配置项需要进行缓存,比如用户信息、设置项开关、服务器IP地址等。如果采用原生的 **SharedPreferences** 来实现的话,则很容易就写出如上所示那样丑陋的代码,不仅需要维护多个数据项的 key 值,而且每次存入和取出数据时都会有一大片重复的代码,不易维护 48 | 49 | 那 DoKV 的表现如何呢? 50 | 51 | 很简单!!! 52 | 53 | 假设你的应用包含了一个 User 类用于缓存用户信息,首先,为该类加上一个注解:**@DoKV** 54 | 55 | ```java 56 | /** 57 | * 作者:leavesC 58 | * 时间:2019/03/17 0:12 59 | * 描述: 60 | * GitHub:https://github.com/leavesC 61 | * Blog:https://www.jianshu.com/u/9df45b87cfdf 62 | */ 63 | @DoKV 64 | public class User { 65 | 66 | private String name; 67 | 68 | private int age; 69 | 70 | private String sex; 71 | 72 | private Book book; 73 | 74 | private List stringList; 75 | 76 | ··· 77 | 78 | } 79 | ``` 80 | 81 | **build** 下工程,DoKV 就会自动为你生成一个以 **类名+DoKV结尾** 的 Java 类(UserDoKV),之后你就可以通过以下这种形式来进行数据存取了,而你无需关心其内部是如何保存的(当然,其内部的缓存机制是可以由你来自定义的) 82 | 83 | ```java 84 | //缓存整个对象 85 | User user = new User(); 86 | user.setAge(24); 87 | user.setName("leavesC"); 88 | UserDoKV.get().setUser(user); 89 | 90 | //获取缓存的对象 91 | User user1 = UserDoKV.get().getUser(); 92 | 93 | //更新本地已缓存的数据的某个设置项 94 | //如果之前没有缓存过,则会自动 new 一个对象并自动赋值 95 | //因为 DoKV 要求注解类必须包含一个无参构造函数,并且包含的字段有对应的 Get 和 Set 方法 96 | UserDoKV.get().setName("leavesCZY"); 97 | UserDoKV.get().setAge(28); 98 | 99 | //移除缓存数据 100 | UserDoKV.get().remove(); 101 | 102 | //移除所有缓存数据 103 | DoKV.clear(); 104 | ``` 105 | 106 | 上文说过,DoKV 是依赖于 APT 技术的,其实际原理就是开发者通过继承 AbstractProcessor 来定义目标代码的生成规则,由编译器根据此规则来生成目标代码,所以 DoKv 的执行效率就如同构造一般的 Java 类,不存在什么依靠反射使性能降低的情况 107 | 108 | UserDoKV 类的定义如下所示: 109 | 110 | ```java 111 | public class UserDoKV extends User { 112 | 113 | private static final String KEY = "leavesc.hello.dokv.model.UserDoKV"; 114 | 115 | private UserDoKV() { 116 | } 117 | 118 | public static UserDoKV get() { 119 | return new UserDoKV(); 120 | } 121 | 122 | private IDoKVHolder getDoKVHolder() { 123 | return DoKV.getInstance().getDoKVHolder(); 124 | } 125 | 126 | private String serialize(String _KEY, User _User) { 127 | return getDoKVHolder().serialize(_KEY, _User); 128 | } 129 | 130 | private User deserialize(String _KEY) { 131 | return getDoKVHolder().deserialize(_KEY, User.class); 132 | } 133 | 134 | public User getUser() { 135 | return deserialize(KEY); 136 | } 137 | 138 | private User getUserNotNull() { 139 | User variable = deserialize(KEY); 140 | if (variable != null) { 141 | return variable; 142 | } 143 | return new User(); 144 | } 145 | 146 | public String setUser(User instance) { 147 | if (instance == null) { 148 | remove(); 149 | return ""; 150 | } 151 | return serialize(KEY, instance); 152 | } 153 | 154 | public void remove() { 155 | getDoKVHolder().remove(KEY); 156 | } 157 | 158 | @Override 159 | public String getName() { 160 | User variable = getUser(); 161 | if (variable != null) { 162 | return variable.getName(); 163 | } 164 | return super.getName(); 165 | } 166 | 167 | @Override 168 | public void setName(String _name) { 169 | User _user = getUserNotNull(); 170 | _user.setName(_name); 171 | serialize(KEY, _user); 172 | } 173 | 174 | //省略类似的 Get/Set 方法 175 | } 176 | ``` 177 | 178 | 179 | 180 | ### 二、自定义缓存 Key 181 | 182 | 在 v0.1.7 版本之前, **DoKV** 默认以**被注解类的类路径**作为缓存 Key,以此来保证 Key 值的唯一性,但考虑到被注解类在后续开发中可能会被移动到其它包下从而导致丢失缓存数据,因为在 v0.1.7 版本中为注解 DoKV 新增了 Key 属性,如果开发者向该属性赋予了值,则以该值作为缓存 Key,而且该 Key 的唯一性需要由开发者自己来保证 183 | 184 | ```java 185 | @DoKV(key = "CustomKeyUser_Key") 186 | public class CustomKeyUser { 187 | 188 | ··· 189 | 190 | } 191 | ``` 192 | 193 | ```java 194 | public class CustomKeyUserDoKV extends CustomKeyUser { 195 | 196 | private static final String KEY = "CustomKeyUser_Key"; 197 | 198 | 199 | ``` 200 | 201 | } 202 | ``` 203 | 204 | 205 | 206 | ### 三、引入 207 | 208 | 为了获得更高的自由度, DoKV 默认将数据持久化的实现方案交由外部来实现,即由使用者来决定如何将对象序列化保存到本地,此时你就可以选择只依赖以下两个引用 209 | 210 | ```groovy 211 | dependencies { 212 | implementation 'leavesc.hello:dokv:xxx' 213 | annotationProcessor 'leavesc.hello:dokv-compiler:xxx' 214 | } 215 | ``` 216 | 217 | 然后,外部将 IDoKVHolder 实例传给 DoKV 即可 218 | 219 | ```java 220 | DoKV.init(new IDoKVHolder() { 221 | 222 | //序列化 223 | @Override 224 | public String serialize(String key, Object src) { 225 | return null; 226 | } 227 | 228 | //反序列化 229 | @Override 230 | public T deserialize(String key, Class classOfT) { 231 | return null; 232 | } 233 | 234 | //移除指定对象 235 | @Override 236 | public void remove(String key) { 237 | 238 | } 239 | 240 | //删除全局的缓存数据 241 | @Override 242 | public void clear() { 243 | 244 | } 245 | }); 246 | ``` 247 | 248 | 如果你不想自己实现 IDoKVHolder ,DoKV 也提供了一个默认实现,此时你就只要多引用如下一个依赖即可,其内部是通过 **Gson + MMKV** 来实现序列化方案 249 | 250 | ```groovy 251 | dependencies { 252 | implementation 'leavesc.hello:dokv-impl:xxx' 253 | } 254 | ``` 255 | 256 | 进行初始化,之后就可以自由地玩耍了 257 | 258 | ```java 259 | DoKV.init(new MMKVDoKVHolder(Context)); 260 | ``` 261 | 262 | 263 | 264 | ### 四、结尾 265 | 266 | 本开源库的 GitHub 主页在这里:[DoKV](https://github.com/leavesC/DoKV) 267 | 268 | APK 下载体检:[DoKV](https://www.pgyer.com/DoKV) 269 | 270 | 我的博客主页:[leavesC](https://www.jianshu.com/u/9df45b87cfdf) 271 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "leavesc.hello.dokv" 7 | minSdkVersion 22 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | lintOptions { 20 | abortOnError false 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation 'com.android.support:appcompat-v7:28.0.0' 27 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 28 | testImplementation 'junit:junit:4.12' 29 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 30 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 31 | implementation project(':dokv_annotation') 32 | annotationProcessor project(':dokv_processor') 33 | implementation project(':dokv_impl') 34 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/leavesc/hello/dokv/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("leavesc.hello.dokv", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/leavesc/hello/dokv/MainActivity.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.text.TextUtils; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.EditText; 9 | import android.widget.TextView; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import leavesc.hello.dokv.model.Book; 15 | import leavesc.hello.dokv.model.CustomKeyUserDoKV; 16 | import leavesc.hello.dokv.model.User; 17 | import leavesc.hello.dokv.model.UserDoKV; 18 | 19 | /** 20 | * 作者:leavesC 21 | * 时间:2019/1/4 23:15 22 | * 描述: 23 | * GitHub:https://github.com/leavesC 24 | * Blog:https://www.jianshu.com/u/9df45b87cfdf 25 | */ 26 | public class MainActivity extends AppCompatActivity { 27 | 28 | private EditText et_userName; 29 | 30 | private EditText et_userAge; 31 | 32 | private EditText et_bookName; 33 | 34 | private EditText et_userSex; 35 | 36 | private Button btn_serializeAll; 37 | 38 | private EditText et_singleUserName; 39 | 40 | private Button btn_serializeSingle; 41 | 42 | private Button btn_remove; 43 | 44 | private Button btn_clear; 45 | 46 | private Button btn_print; 47 | 48 | private TextView tv_hint; 49 | 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_main); 54 | initView(); 55 | btn_serializeAll.setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View v) { 58 | String userName = et_userName.getText().toString(); 59 | String ageStr = et_userAge.getText().toString(); 60 | int age = 0; 61 | if (!TextUtils.isEmpty(ageStr)) { 62 | age = Integer.parseInt(ageStr); 63 | } 64 | User user = new User(); 65 | user.setAge(age); 66 | user.setName(userName); 67 | user.setSex(et_userSex.getText().toString()); 68 | List stringList = new ArrayList<>(); 69 | for (int i = 0; i < 4; i++) { 70 | stringList.add(String.valueOf(i)); 71 | } 72 | user.setStringList(stringList); 73 | Book book = new Book(); 74 | book.setName(et_bookName.getText().toString()); 75 | user.setBook(book); 76 | UserDoKV.get().setUser(user); 77 | } 78 | }); 79 | btn_serializeSingle.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | String userName = et_singleUserName.getText().toString(); 83 | UserDoKV.get().setName(userName); 84 | } 85 | }); 86 | btn_remove.setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | UserDoKV.get().remove(); 90 | } 91 | }); 92 | btn_clear.setOnClickListener(new View.OnClickListener() { 93 | @Override 94 | public void onClick(View v) { 95 | DoKV.clear(); 96 | } 97 | }); 98 | btn_print.setOnClickListener(new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | StringBuilder sb = new StringBuilder(); 102 | sb.append("User : ----->").append(UserDoKV.get().getUser()); 103 | sb.append("\n\n"); 104 | sb.append("User Name : ----->").append(UserDoKV.get().getName()); 105 | 106 | sb.append("\n\n"); 107 | sb.append("CustomKeyUser : ----->").append(CustomKeyUserDoKV.get().getCustomKeyUser()); 108 | 109 | tv_hint.setText(sb); 110 | } 111 | }); 112 | 113 | CustomKeyUserDoKV.get().setKey("这是默认赋予的值"); 114 | } 115 | 116 | private void initView() { 117 | et_userName = findViewById(R.id.et_userName); 118 | et_userAge = findViewById(R.id.et_userAge); 119 | et_bookName = findViewById(R.id.et_bookName); 120 | et_userSex = findViewById(R.id.et_userSex); 121 | btn_serializeAll = findViewById(R.id.btn_serializeAll); 122 | et_singleUserName = findViewById(R.id.et_singleUserName); 123 | btn_serializeSingle = findViewById(R.id.btn_serializeSingle); 124 | btn_remove = findViewById(R.id.btn_remove); 125 | btn_clear = findViewById(R.id.btn_clear); 126 | btn_print = findViewById(R.id.btn_print); 127 | tv_hint = findViewById(R.id.tv_hint); 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /app/src/main/java/leavesc/hello/dokv/MyApplication.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv; 2 | 3 | import android.app.Application; 4 | 5 | import leavesc.hello.dokv_imp.MMKVDoKVHolder; 6 | 7 | /** 8 | * 作者:leavesC 9 | * 时间:2019/1/5 1:06 10 | * 描述: 11 | * GitHub:https://github.com/leavesC 12 | * Blog:https://www.jianshu.com/u/9df45b87cfdf 13 | */ 14 | public class MyApplication extends Application { 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | DoKV.init(new MMKVDoKVHolder(this)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/leavesc/hello/dokv/model/Book.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv.model; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | /** 6 | * 作者:leavesC 7 | * 时间:2019/1/5 15:11 8 | * 描述: 9 | * GitHub:https://github.com/leavesC 10 | * Blog:https://www.jianshu.com/u/9df45b87cfdf 11 | */ 12 | public class Book { 13 | 14 | private String name; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | @NonNull 25 | @Override 26 | public String toString() { 27 | return "Book{" + 28 | "name='" + name + '\'' + 29 | '}'; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/leavesc/hello/dokv/model/CustomKeyUser.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv.model; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import leavesc.hello.dokv.annotation.DoKV; 6 | 7 | /** 8 | * 作者:leavesC 9 | * 时间:2019/4/3 13:41 10 | * 描述: 11 | */ 12 | @DoKV(key = "CustomKeyUser_Key") 13 | public class CustomKeyUser { 14 | 15 | private String key; 16 | 17 | private String value; 18 | 19 | public String getKey() { 20 | return key; 21 | } 22 | 23 | public void setKey(String key) { 24 | this.key = key; 25 | } 26 | 27 | public String getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(String value) { 32 | this.value = value; 33 | } 34 | 35 | @NonNull 36 | @Override 37 | public String toString() { 38 | return "CustomKeyUser{" + 39 | "key='" + key + '\'' + 40 | ", value='" + value + '\'' + 41 | '}'; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/leavesc/hello/dokv/model/User.java: -------------------------------------------------------------------------------- 1 | package leavesc.hello.dokv.model; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.util.List; 6 | 7 | import leavesc.hello.dokv.annotation.DoKV; 8 | 9 | /** 10 | * 作者:leavesC 11 | * 时间:2019/1/5 0:12 12 | * 描述: 13 | * GitHub:https://github.com/leavesC 14 | * Blog:https://www.jianshu.com/u/9df45b87cfdf 15 | */ 16 | @DoKV 17 | public class User { 18 | 19 | private String name; 20 | 21 | private int age; 22 | 23 | private String sex; 24 | 25 | private Book book; 26 | 27 | private List stringList; 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | public int getAge() { 38 | return age; 39 | } 40 | 41 | public void setAge(int age) { 42 | this.age = age; 43 | } 44 | 45 | public String getSex() { 46 | return sex; 47 | } 48 | 49 | public void setSex(String sex) { 50 | this.sex = sex; 51 | } 52 | 53 | public Book getBook() { 54 | return book; 55 | } 56 | 57 | public void setBook(Book book) { 58 | this.book = book; 59 | } 60 | 61 | public List getStringList() { 62 | return stringList; 63 | } 64 | 65 | public void setStringList(List stringList) { 66 | this.stringList = stringList; 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public String toString() { 72 | return "User{" + 73 | "name='" + name + '\'' + 74 | ", age=" + age + 75 | ", sex='" + sex + '\'' + 76 | ", book=" + book + 77 | ", stringList=" + stringList + 78 | '}'; 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 20 | 21 | 28 | 29 | 34 | 35 | 40 | 41 |