Repository: sevenshal/oksharedprefs
Branch: master
Commit: 6ddebe3612eb
Files: 42
Total size: 88.3 KB
Directory structure:
gitextract_7_weegng/
├── .gitignore
├── README.md
├── annotations/
│ ├── .gitignore
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── java/
│ └── cn/
│ └── framework/
│ └── oksharedpref/
│ └── annotations/
│ ├── DefaultValue.java
│ ├── PreferenceType.java
│ ├── SharedPreference.java
│ └── Type.java
├── api/
│ ├── .gitignore
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── cn/
│ └── framework/
│ └── oksharedpref/
│ ├── MPSPUtils.java
│ └── OkSharedPrefContentProvider.java
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── cn/
│ │ └── framework/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── cn/
│ │ │ └── framework/
│ │ │ └── oksharedpref/
│ │ │ └── app/
│ │ │ ├── IMsg.java
│ │ │ ├── MainActivity.java
│ │ │ └── SeActivity.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ └── content_main.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── cn/
│ └── framework/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── processor/
│ ├── .gitignore
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── java/
│ │ └── cn/
│ │ └── framework/
│ │ └── mpsharedpreferences/
│ │ └── annotations/
│ │ └── processor/
│ │ ├── Modifier.java
│ │ ├── Preference.java
│ │ ├── PreferenceHolder.java
│ │ └── SharedPreferencesAnnotationProcessor.java
│ └── resources/
│ └── META-INF/
│ └── services/
│ └── javax.annotation.processing.Processor
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
================================================
FILE: README.md
================================================
# oksharedpref
```
通过注解生成SharedPreferences实现的工具。解决安卓SharedPreferences多进程数据访问不一致的问题。
```
## 简介
1. 让你告别手写包装代码管理SharedPreferences,通过注解的方式定义SharedPreferences包装类,使你可以方便的通过get/set方法操作SharedPreferences。
2. 现在看来,安卓官方基本放弃了解决SharedPreferences跨进程访问不一致这一问题了,跨进程访问数据官方更加推荐ContentProvider。
3. OkSharedPrefs将SharedPreferences和ContentProvider结合起来,让你使用SharedPreferences更加方便,并且通过ContentProvider交换数据,解决了跨进程数据访问不一致的问题。
4. 底层仍然使用系统SharedPreferences实现,所以你的应用之前没有使用oksharedprefs,你可以很方便的移植,在新版本中加入这个库,已安装用户的原有数据不会有任何影响。
## 安装
```groovy
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.sevenshal.oksharedprefs:api:1.0.1'
annotationProcessor 'com.github.sevenshal.oksharedprefs:processor:1.0.1'
}
```
## 用法
定一个interface类并且如下所示添加注解:
```java
@SharedPreference(value = "Msg", implSharedPreference = false, preferenceName = "msg", multiProcess = false)
public interface IMsg {
@DefaultValue(value = "null", createDefaultGetter = false)
String USERID = "userId";
@Type(PreferenceType.STRING_SET)
@DefaultValue(value = "null", createDefaultGetter = false)
String TOKEN = "token";
@Type(PreferenceType.LONG)
@DefaultValue(value = "0", createDefaultGetter = false)
String DEVICE_ID = "deviceId";
@Type(PreferenceType.BOOLEAN)
@DefaultValue(value = "false", createDefaultGetter = false)
String LOGIN = "hasAuth";
String NICK_NAME = "nickName";
}
```
然后就可以直接使用生成的包装类了:
``` java
MsgPrefs msgPrefs = MsgPrefs.defaultInstance(this);
long deviceId = msgPrefs.getDeviceId();
String userId = msgPrefs.getUserid();
boolean login = msgPrefs.isLogin();
String nickName= msgPrefs.getNickName("未命名");
msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);
Set set = new HashSet<String>();
set.add("a");
set.add("b");
msgPrefs.edit().setDeviceId(111).setLogin(true).setUserid("userid").setToken(set).apply();
```
## 说明
生成的类的名称通过 @SharedPreference 的 value属性定义。生成的类名称为 value+Prefs,比如
@SharedPreference(value = "Msg") 将生成 MsgPrefs 类。
如果你不希望以Prefs结尾,可以通过preferencesSuffix属性修改。
@SharedPreference(value = "Msg", preferencesSuffix = "Preferences") 将生成 MsgPreferences类。
OkSharedPrefs生成的包装类默认实现了SharedPreferences接口,
这在key值通过变量方式存取时很方便,如果不希望生成的类实现SharedPreferences接口,
可以通过将 implSharedPreference 设置为 false,关闭该功能。此种情况下,可以通过生成的类的prefs()获取SharedPreferences接口实例。
默认的SharedPreferences文件名为default_preferences,你可以通过 preferenceName 修改。
**默认生成的包装类不支持跨进程,但是可以通过将 multiProcess 设置为true打开该功能,默认关闭该功能是出于性能考虑,减少生成不必要的代码。**
生成的包装类是单例模式的,因为安卓底层SharedPreferences也是全局单实例的,所以不会单例模式并不会带来性能问题。
考虑到在插件化系统中Context可能会做隔离的使用场景,你仍然可以通过 new MsgPrefs(context)的方式来使用。
甚至可以new MsgPrefs(context,name)来通过相同结构的包装类管理不同的属性文件,这对那种多用户数据管理的app很有用。
所有属性默认类型是String类型,通过为interface的属性添加
@Type(PreferenceType.LONG)
来修改类型。支持完整的SharedPreferences数据类型。
通过 @DefaultValue(value = "null", createDefaultGetter = false) 可以设置默认值,以及是否生成默认值取值方法。
createDefaultGetter的取值意义在于你是希望通过 msgPrefs.getNickName("自定义默认值") 还是 msgPrefs.getNickName() 获取数据。如果你在编码期间不确定默认值是什么,那需要将createDefaultGetter设为true。
================================================
FILE: annotations/.gitignore
================================================
/build
================================================
FILE: annotations/build.gradle
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
buildscript {
repositories {
mavenLocal()
// mavenCentral()
}
}
apply plugin: 'java'
apply plugin: 'maven'
//apply plugin: 'signing'
compileJava {
sourceCompatibility = 1.6
targetCompatibility = 1.7
}
archivesBaseName = "annotations"
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.android:android:4.1.1.4'
}
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}
artifacts {
archives javadocJar, sourcesJar
}
//signing {
// sign configurations.archives
//}
def ossrhUsername = System.properties['ossrhUsername']
def ossrhPassword = System.properties['ossrhPassword']
uploadArchives {
repositories {
mavenDeployer {
repository(url: mavenLocal().getUrl())
// beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
//
// repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
// authentication(userName: ossrhUsername, password: ossrhPassword)
// }
//
// snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
// authentication(userName: ossrhUsername, password: ossrhPassword)
// }
//
// pom.project {
// name 'SharedPreferences Annotations'
// packaging 'jar'
// // optionally artifactId can be defined here
// description 'Annotations to generate Source Code ' +
// 'used by the Annotation Processor in cn.framework.oksharedpref:processor'
// url 'https://github.com/sevenshal/oksharedpref-api'
//
// scm {
// connection 'scm:git:ssh://git@github.com/sevenshal/oksharedpref-api.git'
// developerConnection 'scm:git:ssh://git@github.com/sevenshal/oksharedpref-api.git'
// url 'https://github.com/sevenshal/oksharedpref-api'
// }
//
// licenses {
// license {
// name 'MIT License'
// url 'http://www.opensource.org/licenses/mit-license.php'
// }
// }
//
// developers {
// developer {
// id 'sevenshal'
// name 'David Medenjak'
// email 'davidmedenjak@gmail.com'
// url 'https://github.com/sevenshal '
// roles {
// role 'owner'
// role 'developer'
// }
// timezone '+1'
// }
// }
// }
}
}
}
================================================
FILE: annotations/src/main/java/cn/framework/oksharedpref/annotations/DefaultValue.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to set the default value for this preference. THis value is supplied as String, because
* the code is generated and the value simply inserted as is. Please be sure to support a valid
* value.
* <p>By setting {@link #createDefaultGetter} to <b>false</b> you
* can suppress the additional getter of the form <em>get(Type defaultValue)</em>.</p>
*
* @author sevenshal
* @version 1.0
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface DefaultValue {
/**
* Supplies the default value to use for a preference in String format. e.g. "3.0f", "hi", ...
* @return the value to use as String.
*/
String value();
/**
* Used to specify the creation of the default getter of the form <em>get(Type defaultValue)</em>.
* @return default true, to create the default getter nonetheless.
*/
boolean createDefaultGetter() default true;
}
================================================
FILE: annotations/src/main/java/cn/framework/oksharedpref/annotations/PreferenceType.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations;
/**
* The usable types of the properties in the preferences. Used to set the return type
* and parameters.
* <p>
* {@link #BOOLEAN}</p><p>
* {@link #FLOAT}</p><p>
* {@link #INTEGER}</p><p>
* {@link #LONG}</p><p>
* {@link #STRING}</p><p>
* {@link #STRING_SET}</p>
*
* @author sevenshal
* @version 1.0
*/
public enum PreferenceType {
/**
* Standard java boolean.
*
* @see Boolean
*/
BOOLEAN("boolean", "Boolean"),
/**
* Standard java floating point number.
*
* @see Float
*/
FLOAT("float", "Float"),
/**
* Standard java number.
*
* @see Integer
*/
INTEGER("int", "Int"),
/**
* Standard java long.
*
* @see Long
*/
LONG("long", "Long"),
/**
* Standard java String.
*
* @see String
*/
STRING("String", "String"),
/**
* A set of Strings.
*
* @see String
* @see java.util.Set
*/
STRING_SET("Set<String>", "StringSet");
private String returnType;
private String fullName;
PreferenceType(String returnType, String fullName) {
this.returnType = returnType;
this.fullName = fullName;
}
/**
* Method to supply the spelling for the type as a return type.
*
* @return the type as String usable for method declarations.
*/
public String getReturnType() {
return returnType;
}
/**
* Method to supply the type as a String used for the getter methods. e.g. <em>getString()</em>
*
* @return the type as String, CamelCase.
*/
public String getFullName() {
return fullName;
}
}
================================================
FILE: annotations/src/main/java/cn/framework/oksharedpref/annotations/SharedPreference.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>Annotation to generate a default wrapper class for the annotated interface.
* Supply a String value
* to change the name of the genereated class to <i>value</i>Prefs and <i>value</i>Editor.
* </p>
* <p>By not specifying a value <i>DefaultPrefs</i> and <i>DefaultEditor</i> will be generated.</p>
* <p>
* <p>Additionally you may change the class name suffixes by setting {@link #preferencesSuffix()}
* or {@link #editorSuffix()}.</p>
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface SharedPreference {
/**
* the prefix for the generated preferences and editor.
*
* @return the prefix, the name of the annotated interface by default.
*/
String value() default "";
/**
* the suffix for the preferences.
*
* @return the suffix, "Prefs" by default.
*/
String preferencesSuffix() default "Prefs";
/**
* preferences name which used by getSharedPreferences(preferenceName).
* @return the name, "default_preferences" by default.
*/
String preferenceName() default "default_preferences";
/**
* Set the default type for all the contained properties in the interface if not specified.
* To use a different type for a single property
* annotate the properties with {@link Type}.
* @return the default type, PreferenceType.STRING by default.
*/
PreferenceType defaultPreferenceType() default PreferenceType.STRING;
/**
* the suffix for the editor.
*
* @return the suffix, "Editor" by default.
*/
String editorSuffix() default "Editor";
/**
* implement interface of SharedPreference if true
*
* @return true
*/
boolean implSharedPreference() default true;
/**
* the sharedpreference can be used in multiprocess safely if true.
* @return
*/
boolean multiProcess() default false;
}
================================================
FILE: annotations/src/main/java/cn/framework/oksharedpref/annotations/Type.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>The preferences type of this single property.
* The getter and setter will be genereated with the supplied type.</p>
* Supported types are of {@link PreferenceType}
*
* @author sevenshal
* @version 1.0
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface Type {
/**
* the type of the preference element.
*
* @return the type
*/
PreferenceType value();
/**
* <b>if</b> the type is a boolean, you can set the getter prefix here.
*
* @return the prefix for the getter, "is" by default.
*/
String booleanPrefix() default "is";
}
================================================
FILE: api/.gitignore
================================================
/build
================================================
FILE: api/build.gradle
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
buildscript {
repositories {
mavenLocal()
// mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'maven'
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
minSdkVersion 11
targetSdkVersion 26
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
archivesBaseName = "api"
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':annotations')
}
//signing {
// sign configurations.archives
//}
def ossrhUsername = System.properties['ossrhUsername']
def ossrhPassword = System.properties['ossrhPassword']
uploadArchives {
repositories {
mavenDeployer {
repository(url: mavenLocal().getUrl())
}
}
}
================================================
FILE: api/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.framework.oksharedpref">
<application>
<provider android:name="cn.framework.oksharedpref.OkSharedPrefContentProvider"
android:authorities="${applicationId}.oksharedpref" />
</application>
</manifest>
================================================
FILE: api/src/main/java/cn/framework/oksharedpref/MPSPUtils.java
================================================
package cn.framework.oksharedpref;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ProviderInfo;
import android.os.Process;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Locale;
/**
* Created by sevenshal on 2017/10/26.
*/
public class MPSPUtils {
private static Boolean isProviderProcess;
private static boolean isProviderProcess(Context ctx) {
if (isProviderProcess != null) {
return isProviderProcess;
}
String processCmdPath = String.format(Locale.getDefault(),
"/proc/%d/cmdline", Process.myPid());
BufferedReader inputStream = null;
try {
inputStream = new BufferedReader(new FileReader(
processCmdPath));
String processName = inputStream.readLine().trim();
ProviderInfo providerInfo = ctx.getPackageManager().getProviderInfo(new ComponentName(ctx, OkSharedPrefContentProvider.class), 0);
isProviderProcess = TextUtils.equals(providerInfo.processName, processName);
return isProviderProcess;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static SharedPreferences getSharedPref(Context ctx, String name) {
SharedPreferences preferences;
if (MPSPUtils.isProviderProcess(ctx)) {
preferences = ctx.getSharedPreferences(name, Context.MODE_PRIVATE);
} else {
preferences = OkSharedPrefContentProvider.getSharedPreferences(ctx, name, Context.MODE_PRIVATE);
}
return preferences;
}
}
================================================
FILE: api/src/main/java/cn/framework/oksharedpref/OkSharedPrefContentProvider.java
================================================
package cn.framework.oksharedpref;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* 使用ContentProvider实现多进程SharedPreferences读写
*/
public class OkSharedPrefContentProvider extends ContentProvider {
private static final String TAG = "MPSP";
private static String AUTHORITY;
private static volatile Uri AUTHORITY_URI;
private static final String METHOD_MP = "multi_process";
private static final String KEY = "key";
private static final String KEY_TYPE = "type";
private static final String KEY_MODE = "mode";
private static final String KEY_VALUE = "value";
private static final String KEY_CLEAR = "clear";
private static final int GET_ALL = 1;
private static final int GET_STRING = 2;
private static final int GET_INT = 3;
private static final int GET_LONG = 4;
private static final int GET_FLOAT = 5;
private static final int GET_BOOLEAN = 6;
private static final int GET_STRING_SET = 7;
private static final int CONTAINS = 8;
private static final int APPLY = 9;
private static final int COMMIT = 10;
private HashMap<String, SharedPreferences.OnSharedPreferenceChangeListener> listenerHashMap;
private static Bundle handle(SharedPreferences sp, Bundle extras) {
String key = extras.getString(KEY);
int type = extras.getInt(KEY_TYPE);
Bundle bundle = new Bundle();
switch (type) {
case GET_ALL:
bundle.putSerializable(KEY_VALUE, new HashMap(sp.getAll()));
break;
case GET_STRING:
bundle.putString(KEY_VALUE, sp.getString(key, extras.getString(KEY_VALUE)));
break;
case GET_INT:
bundle.putInt(KEY_VALUE, sp.getInt(key, extras.getInt(KEY_VALUE)));
break;
case GET_LONG:
bundle.putLong(KEY_VALUE, sp.getLong(key, extras.getLong(KEY_VALUE)));
break;
case GET_FLOAT:
bundle.putFloat(KEY_VALUE, sp.getFloat(key, extras.getFloat(KEY_VALUE)));
break;
case GET_BOOLEAN:
bundle.putBoolean(KEY_VALUE, sp.getBoolean(key, extras.getBoolean(KEY_VALUE)));
break;
case GET_STRING_SET:
bundle.putSerializable(KEY_VALUE, wrapperSet(
sp.getStringSet(key, (Set<String>) extras.getSerializable(KEY_VALUE))));
break;
case CONTAINS:
bundle.putBoolean(KEY_VALUE, sp.contains(key));
break;
case APPLY:
case COMMIT:
boolean clear = extras.getBoolean(KEY_CLEAR, false);
SharedPreferences.Editor editor = sp.edit();
if (clear) {
editor.clear();
}
HashMap<String, ?> values = (HashMap) extras.getSerializable(KEY_VALUE);
for (Map.Entry entry : values.entrySet()) {
String k = (String) entry.getKey();
Object v = entry.getValue();
if (v == null) {
editor.remove(k);
} else if (v instanceof String) {
editor.putString(k, (String) v);
} else if (v instanceof Set) {
editor.putStringSet(k, (Set) v);
} else if (v instanceof Integer) {
editor.putInt(k, (Integer) v);
} else if (v instanceof Long) {
editor.putLong(k, (Long) v);
} else if (v instanceof Float) {
editor.putFloat(k, (Float) v);
} else if (v instanceof Boolean) {
editor.putBoolean(k, (Boolean) v);
}
}
if (type == APPLY) {
editor.apply();
bundle.putBoolean(KEY_VALUE, true);
} else {
bundle.putBoolean(KEY_VALUE, editor.commit());
}
break;
default:
break;
}
return bundle;
}
@Override
public Bundle call(String method, String name, Bundle extras) {
if (!method.equals(METHOD_MP)) {
return null;
}
int mode = extras.getInt(KEY_MODE);
SharedPreferences sp = getContext().getSharedPreferences(name, mode);
registListener(sp, name);
return handle(sp, extras);
}
void registListener(SharedPreferences pref, final String name) {
if (listenerHashMap == null || listenerHashMap.get(name) == null) {
synchronized (MPSPUtils.class) {
if (listenerHashMap == null) {
listenerHashMap = new HashMap<>();
}
if (listenerHashMap.get(name) == null) {
SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences
.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Uri uri = Uri.withAppendedPath(OkSharedPrefContentProvider.getAuthorityUri(getContext(), name), key);
getContext().getContentResolver().notifyChange(uri, null);
}
};
pref.registerOnSharedPreferenceChangeListener(listener);
listenerHashMap.put(name, listener);
}
}
}
}
/**
* 如果设备处在“安全模式”下,只有系统自带的ContentProvider才能被正常解析使用;
*/
private static boolean isSafeMode(Context context) {
boolean isSafeMode = false;
try {
isSafeMode = context.getPackageManager().isSafeMode();
// 解决崩溃:
// java.lang.RuntimeException: Package manager has died
// at android.app.ApplicationPackageManager.isSafeMode(ApplicationPackageManager.java:820)
} catch (RuntimeException e) {
e.printStackTrace();
}
return isSafeMode;
}
public static Uri getAuthorityUri(Context context, String name) {
if (AUTHORITY_URI == null) {
synchronized (OkSharedPrefContentProvider.class) {
if (AUTHORITY_URI == null) {
if (AUTHORITY == null) {
AUTHORITY = context.getPackageName() + ".oksharedpref";
}
AUTHORITY_URI = Uri.parse(ContentResolver.SCHEME_CONTENT + "://" + AUTHORITY);
}
}
}
return Uri.withAppendedPath(AUTHORITY_URI, name);
}
/**
* 获取异常栈中最底层的 Throwable Cause;
*
* @param tr
* @return
*/
private static Throwable getLastCause(Throwable tr) {
Throwable cause = tr.getCause();
Throwable causeLast = null;
while (cause != null) {
causeLast = cause;
cause = cause.getCause();
}
if (causeLast == null) {
causeLast = new Throwable();
}
return causeLast;
}
/**
* mode不使用{@link Context#MODE_MULTI_PROCESS}特可以支持多进程了;
*
* @param mode
* @see Context#MODE_PRIVATE
* @see Context#MODE_WORLD_READABLE
* @see Context#MODE_WORLD_WRITEABLE
*/
public static SharedPreferences getSharedPreferences(Context context, String name, int mode) {
return isSafeMode(context) ? context.getSharedPreferences(name, mode) : new SharedPreferencesImpl(context, name, mode);
}
/**
* @deprecated 此默认构造函数只用于父类ContentProvider在初始化时使用;
*/
@Deprecated
public OkSharedPrefContentProvider() {
}
private static final class SharedPreferencesImpl implements SharedPreferences {
private static Handler uiHandler = new Handler(Looper.getMainLooper());
private Context mContext;
private String mName;
private int mMode;
private WeakHashMap<OnSharedPreferenceChangeListener, ContentObserverImplHolder> mListeners;
private SharedPreferencesImpl(Context context, String name, int mode) {
mContext = context;
mName = name;
mMode = mode;
}
@SuppressWarnings("unchecked")
@Override
public Map<String, ?> getAll() {
Map<String, ?> value = (Map<String, ?>) call(null, GET_ALL, new Bundle());
return value == null ? new HashMap<String, Object>() : value;
}
@Override
public String getString(String key, String defValue) {
Bundle arg = new Bundle();
arg.putString(KEY_VALUE, defValue);
return (String) call(key, GET_STRING, arg);
}
@Override
@SuppressWarnings("unchecked")
public Set<String> getStringSet(String key, Set<String> defValues) {
Bundle arg = new Bundle();
arg.putSerializable(KEY_VALUE, wrapperSet(defValues));
return (Set<String>) call(key, GET_STRING_SET, arg);
}
@Override
public int getInt(String key, int defValue) {
Bundle arg = new Bundle();
arg.putInt(KEY_VALUE, defValue);
return (Integer) call(key, GET_INT, arg);
}
@Override
public long getLong(String key, long defValue) {
Bundle arg = new Bundle();
arg.putLong(KEY_VALUE, defValue);
return (Long) call(key, GET_LONG, arg);
}
@Override
public float getFloat(String key, float defValue) {
Bundle arg = new Bundle();
arg.putFloat(KEY_VALUE, defValue);
return (Float) call(key, GET_FLOAT, arg);
}
@Override
public boolean getBoolean(String key, boolean defValue) {
Bundle arg = new Bundle();
arg.putBoolean(KEY_VALUE, defValue);
return (Boolean) call(key, GET_BOOLEAN, arg);
}
@Override
public boolean contains(String key) {
return (Boolean) call(key, CONTAINS, new Bundle());
}
@Override
public Editor edit() {
return new EditorImpl();
}
@Override
public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) {
Uri uri = getAuthorityUri(mContext, mName);
ContentObserverImplHolder observer = new ContentObserverImplHolder(listener);
mContext.getContentResolver()
.registerContentObserver(uri, true, observer.observer);
getListeners().put(listener, observer);
}
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
ContentObserverImplHolder holder = getListeners().remove(listener);
if (holder != null) {
holder.observer.destroy();
}
}
private Map<OnSharedPreferenceChangeListener, ContentObserverImplHolder> getListeners() {
if (mListeners == null) {
synchronized (this) {
if (mListeners == null) {
mListeners = new WeakHashMap<>();
}
}
}
return mListeners;
}
private class ContentObserverImplHolder {
ContentObserverImpl observer;
ContentObserverImplHolder(OnSharedPreferenceChangeListener listener) {
observer = new ContentObserverImpl(listener);
}
@Override
protected void finalize() throws Throwable {
try {
observer.destroy();
} catch (Throwable e) {
e.printStackTrace();
}
super.finalize();
}
}
private class ContentObserverImpl extends ContentObserver {
private WeakReference<OnSharedPreferenceChangeListener> listenerRef;
private boolean destroy;
private ContentObserverImpl(OnSharedPreferenceChangeListener listener) {
super(uiHandler);
this.listenerRef = new WeakReference<OnSharedPreferenceChangeListener>(listener);
}
public void destroy() {
if (!destroy) {
synchronized (this) {
if (!destroy) {
mContext.getContentResolver()
.unregisterContentObserver(this);
destroy = true;
}
}
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
OnSharedPreferenceChangeListener listener = listenerRef.get();
if (listener != null) {
listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, uri.getLastPathSegment());
} else {
destroy();
}
}
}
private Object call(String key, int type, Bundle arg) {
Uri uri = getAuthorityUri(mContext, mName);
arg.putInt(KEY_MODE, mMode);
arg.putString(KEY, key);
arg.putInt(KEY_TYPE, type);
try {
Bundle ret = mContext.getContentResolver().call(uri, METHOD_MP, mName, arg);
return ret.get(KEY_VALUE);
} catch (Throwable e) {
e.printStackTrace();
return handle(mContext.getSharedPreferences(mName, mMode), arg).get(KEY_VALUE);
}
}
public final class EditorImpl implements Editor {
private final HashMap<String, Object> mModified = new HashMap();
private boolean mClear = false;
@Override
public Editor putString(String key, String value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
@Override
public Editor putStringSet(String key, Set<String> values) {
synchronized (this) {
mModified.put(key, values);
return this;
}
}
@Override
public Editor putInt(String key, int value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
@Override
public Editor putLong(String key, long value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
@Override
public Editor putFloat(String key, float value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
@Override
public Editor putBoolean(String key, boolean value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
@Override
public Editor remove(String key) {
synchronized (this) {
mModified.put(key, null);
return this;
}
}
@Override
public Editor clear() {
synchronized (this) {
mModified.clear();
mClear = true;
return this;
}
}
@Override
public void apply() {
setValue(APPLY);
}
@Override
public boolean commit() {
return setValue(COMMIT);
}
private boolean setValue(int type) {
Bundle extras = new Bundle();
extras.putSerializable(KEY_VALUE, mModified);
extras.putBoolean(KEY_CLEAR, mClear);
return (Boolean) call(null, type, extras);
}
}
}
private static HashSet<String> wrapperSet(Set<String> set) {
return set == null ? null : (set instanceof HashMap ? (HashSet<String>) set : new HashSet<String>(set));
}
private static String makeAction(String name) {
return String.format("%1$s_%2$s", OkSharedPrefContentProvider.class.getName(), name);
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
throw new UnsupportedOperationException(" No external query");
}
@SuppressWarnings("unchecked")
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException(" No external update");
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("No external call");
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("No external insert");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("No external delete");
}
}
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "cn.framework.sharedpref.app"
minSdkVersion 11
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.github.sevenshal.oksharedprefs:api:1.0.1'
annotationProcessor 'com.github.sevenshal.oksharedprefs:processor:1.0.1'
// compile project(':api')
// annotationProcessor project(':processor')
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/sevenshal/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app/src/androidTest/java/cn/framework/ExampleInstrumentedTest.java
================================================
package cn.framework;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("cn.framework", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.framework">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".oksharedpref.app.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".oksharedpref.app.SeActivity"
android:label="@string/app_name"
android:process=":new"
android:theme="@style/AppTheme.NoActionBar">
</activity>
</application>
</manifest>
================================================
FILE: app/src/main/java/cn/framework/oksharedpref/app/IMsg.java
================================================
package cn.framework.oksharedpref.app;
import cn.framework.oksharedpref.annotations.DefaultValue;
import cn.framework.oksharedpref.annotations.PreferenceType;
import cn.framework.oksharedpref.annotations.SharedPreference;
import cn.framework.oksharedpref.annotations.Type;
/**
* Created by sevenshal on 2016/11/28.
*/
@SharedPreference(value = "Msg", implSharedPreference = false, preferenceName = "msg", multiProcess = false)
public interface IMsg {
@DefaultValue(value = "null", createDefaultGetter = false)
String USERID = "userId";
@Type(PreferenceType.STRING_SET)
@DefaultValue(value = "null", createDefaultGetter = false)
String TOKEN = "token";
@Type(PreferenceType.LONG)
@DefaultValue(value = "0", createDefaultGetter = false)
String DEVICE_ID = "deviceId";
@Type(PreferenceType.BOOLEAN)
@DefaultValue(value = "false", createDefaultGetter = false)
String LOGIN = "hasAuth";
String NICK_NAME = "nickName";
}
================================================
FILE: app/src/main/java/cn/framework/oksharedpref/app/MainActivity.java
================================================
package cn.framework.oksharedpref.app;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.util.HashSet;
import java.util.Set;
import cn.framework.R;
public class MainActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
MsgPrefs msgPrefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SeActivity.class));
}
});
msgPrefs = MsgPrefs.defaultInstance(this);
Log.i("MPM", "deviceId:" + msgPrefs.getDeviceId()
+ ";userId:" + msgPrefs.getUserid()
+ ";isLogin:" + msgPrefs.isLogin() + ";token:" + msgPrefs.getToken());
msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);
Set set = new HashSet<String>();
set.add("a");
set.add("b");
msgPrefs.edit().setDeviceId(111).setLogin(true).setUserid("userid").setToken(set).apply();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.i("MP", "main_onSharedPreferenceChanged:" + key);
Log.i("MPM", "deviceId:" + msgPrefs.getDeviceId()
+ ";userId:" + msgPrefs.getUserid()
+ ";isLogin:" + msgPrefs.isLogin() + ";token:" + msgPrefs.getToken());
}
}
================================================
FILE: app/src/main/java/cn/framework/oksharedpref/app/SeActivity.java
================================================
package cn.framework.oksharedpref.app;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
/**
* Created by sevenshal on 2017/10/23.
*/
public class SeActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
MsgPrefs msgPrefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
msgPrefs = MsgPrefs.defaultInstance(this);
Log.i("MPM", "deviceId:" + msgPrefs.getDeviceId()
+ ";userId:" + msgPrefs.getUserid()
+ ";isLogin:" + msgPrefs.isLogin() + ";token:" + msgPrefs.getToken());
Set set = new HashSet<String>();
set.add("a2");
set.add("b2");
msgPrefs.prefs().registerOnSharedPreferenceChangeListener(this);
msgPrefs.edit().setToken(set).setUserid("userid2").setLogin(false).setDeviceId(222).apply();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.i("MP", "onSharedPreferenceChanged:" + key);
Log.i("MPM", "deviceId:" + msgPrefs.getDeviceId()
+ ";userId:" + msgPrefs.getUserid()
+ ";isLogin:" + msgPrefs.isLogin() + ";token:" + msgPrefs.getToken());
}
@Override
protected void onDestroy() {
super.onDestroy();
msgPrefs.prefs().unregisterOnSharedPreferenceChangeListener(this);
}
}
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="startNewProcessActivity"/>
</LinearLayout>
================================================
FILE: app/src/main/res/layout/content_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">MultiProcessSharepref</string>
<string name="action_settings">Settings</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme">
<!-- Customize your theme here. -->
</style>
<style name="AppTheme.NoActionBar" parent="android:Theme.Holo.NoActionBar">
</style>
<style name="AppTheme.AppBarOverlay" parent="android:Theme" />
<style name="AppTheme.PopupOverlay" parent="android:Theme.Holo.Light" />
</resources>
================================================
FILE: app/src/test/java/cn/framework/ExampleUnitTest.java
================================================
package cn.framework;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenLocal()
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven { url 'https://jitpack.io' }
}
group = 'cn.framework.oksharedpref'
version = '1.0.0'
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Nov 01 14:56:37 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: processor/.gitignore
================================================
/build
================================================
FILE: processor/build.gradle
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
buildscript {
repositories {
mavenLocal()
// mavenCentral()
}
}
apply plugin: 'java'
apply plugin: 'maven'
//apply plugin: 'signing'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':annotations')
compile 'com.squareup:javawriter:2.5.1'
compile 'com.google.android:android:4.1.1.4'
}
archivesBaseName = "processor"
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}
artifacts {
archives javadocJar, sourcesJar
}
//signing {
// sign configurations.archives
//}
def ossrhUsername = System.properties['ossrhUsername']
def ossrhPassword = System.properties['ossrhPassword']
uploadArchives {
repositories {
mavenDeployer {
repository(url: mavenLocal().getUrl())
}
}
}
================================================
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Modifier.java
================================================
package cn.framework.oksharedpref.annotations.processor;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Created by David on 25.01.2015.
*/
class Modifier {
final static Set<javax.lang.model.element.Modifier> PUBLIC_STATIC = new LinkedHashSet<>();
final static Set<javax.lang.model.element.Modifier> PUBLIC = new LinkedHashSet<>();
final static Set<javax.lang.model.element.Modifier> PRIVATE = new LinkedHashSet<>();
final static Set<javax.lang.model.element.Modifier> PRIVATE_STATIC = new LinkedHashSet<>();
final static Set<javax.lang.model.element.Modifier> PRIVATE_FINAL = new LinkedHashSet<>();
final static Set<javax.lang.model.element.Modifier> PUBLIC_FINAL_STATIC = new LinkedHashSet<>();
static {
PUBLIC_STATIC.add(javax.lang.model.element.Modifier.PUBLIC);
PUBLIC_STATIC.add(javax.lang.model.element.Modifier.STATIC);
PUBLIC.add(javax.lang.model.element.Modifier.PUBLIC);
PRIVATE_FINAL.add(javax.lang.model.element.Modifier.PRIVATE);
PRIVATE_FINAL.add(javax.lang.model.element.Modifier.FINAL);
PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.PUBLIC);
PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.FINAL);
PUBLIC_FINAL_STATIC.add(javax.lang.model.element.Modifier.STATIC);
PRIVATE.add(javax.lang.model.element.Modifier.PRIVATE);
PRIVATE_STATIC.add(javax.lang.model.element.Modifier.PRIVATE);
PRIVATE_STATIC.add(javax.lang.model.element.Modifier.STATIC);
}
}
================================================
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Preference.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations.processor;
import com.squareup.javawriter.JavaWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import cn.framework.oksharedpref.annotations.DefaultValue;
import cn.framework.oksharedpref.annotations.PreferenceType;
import cn.framework.oksharedpref.annotations.Type;
/**
* @author sevenshal
* @version 1.0
*/
public class Preference {
private static final Set<Modifier> setPublic;
static {
setPublic = new HashSet<>();
setPublic.add(Modifier.PUBLIC);
}
private static final String PARAM_DEFAULT_VALUE = "defaultValue";
private static final String VALUE = "value";
private final VariableElement mElement;
private final PreferenceType mType;
private final String mPreferenceName;
private final String mpreferenceFieldName;
private final String mPreferenceId;
private final String mBooleanPrefix;
private final boolean hasDefaultValue;
private final boolean createDefaultGetter;
private final String mDefaultValue;
public static String camelCaseName(String name) {
String[] split = name.toLowerCase().split("_");
String ret = split[0];
for (int i = 1; i < split.length; i++) {
ret += Character.toUpperCase(split[i].charAt(0)) + split[i].substring(1);
}
return ret;
}
public Preference(String preferenceName, String preferenceId, VariableElement element, PreferenceType defaultType) {
String camelCaseName = camelCaseName(preferenceName);
mPreferenceName = Character.toUpperCase(camelCaseName.charAt(0)) + camelCaseName.substring(1);
mpreferenceFieldName = preferenceName;
mPreferenceId = preferenceId;
mElement = element;
Type type = element.getAnnotation(Type.class);
if (type == null) {
mType = defaultType != null ? defaultType : PreferenceType.STRING;
mBooleanPrefix = "is";
} else {
mType = type.value();
mBooleanPrefix = type.booleanPrefix();
}
DefaultValue defValue = element.getAnnotation(DefaultValue.class);
if (defValue != null) {
hasDefaultValue = true;
mDefaultValue = defValue.value();
createDefaultGetter = defValue.createDefaultGetter();
} else {
hasDefaultValue = false;
createDefaultGetter = true;
mDefaultValue = null;
}
}
public VariableElement getElement() {
return mElement;
}
public void writeGetter(JavaWriter writer) throws IOException {
final String prefix = mType == PreferenceType.BOOLEAN ? mBooleanPrefix : "get";
// Create getter() for default value
if (hasDefaultValue) {
writer.emitEmptyLine().emitJavadoc("gets '%s' from the preferences, <b>%s</b> by default if not yet set.", mPreferenceId, mDefaultValue)
.beginMethod(mType.getReturnType(), prefix + mPreferenceName, setPublic)
.emitStatement("return mPreferences.get%1$s(%2$s, %3$s)", mType.getFullName(), mpreferenceFieldName, mDefaultValue).endMethod();
}
if (!createDefaultGetter)
return;
writer.emitEmptyLine().emitJavadoc("gets '%s' from the preferences.\n@param %s the default value to use", mPreferenceId, PARAM_DEFAULT_VALUE)
.beginMethod(mType.getReturnType(), prefix + mPreferenceName, setPublic, mType.getReturnType(), PARAM_DEFAULT_VALUE)
.emitStatement("return mPreferences.get%1$s(%2$s, %3$s)", mType.getFullName(), mpreferenceFieldName, PARAM_DEFAULT_VALUE).endMethod();
}
public void writeSetter(JavaWriter writer) throws IOException {
writer.emitEmptyLine().emitJavadoc("sets '%1$s' in the preferences.\n@param %2$s the new value for '%1$s'", mPreferenceId, VALUE)
.beginMethod("void", "set" + mPreferenceName, setPublic, mType.getReturnType(), VALUE)
.emitStatement("mPreferences.edit().put%1$s(%2$s, %3$s).apply()", mType.getFullName(), mpreferenceFieldName, VALUE)
.endMethod();
}
public void writeChainSetter(JavaWriter writer, String editorType, String editor) throws IOException {
writer.emitEmptyLine().emitJavadoc("sets '%1$s' in the preferences.\n@param %2$s the new value for '%1$s'", mPreferenceId, VALUE)
.beginMethod(editorType, "set" + mPreferenceName, setPublic, mType.getReturnType(), VALUE)
.emitStatement("%1$s.put%2$s(%3$s, %4$s)", editor, mType.getFullName(), mpreferenceFieldName, VALUE)
.emitStatement("return this")
.endMethod();
}
}
================================================
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/PreferenceHolder.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations.processor;
import android.content.Context;
import android.content.SharedPreferences;
import com.squareup.javawriter.JavaWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import cn.framework.oksharedpref.annotations.PreferenceType;
import cn.framework.oksharedpref.annotations.SharedPreference;
/**
* @author sevenshal
* @version 1.0
*/
public class PreferenceHolder {
private final static String PAR_CONTEXT = "ctx";
private final static String PAR_NAME = "name";
private final static String PAR_EDITOR = "editor";
private final static String PREFERENCES = "mPreferences";
private static final String EDITOR = "mEditor";
private final static String DEFAULT_INSTANCE = "instance";
private static final String DEFAULT_PREFERENCES_NAME = "default_preferences";
private final TypeElement mElement;
private final JavaWriter mWriter;
private final String preferencesName;
private final String className;
private final String editorName;
private final boolean implSharedPreference;
private final boolean multiProcess;
private final SortedMap<String, Preference> preferences = new TreeMap<>();
public PreferenceHolder(TypeElement element, Filer filer, Messager messager) throws IOException {
this.mElement = element;
// Set the name of the file / class and nested editor
SharedPreference sharedPreference = mElement.getAnnotation(SharedPreference.class);
final String name = (sharedPreference.value().isEmpty()) ? mElement.getSimpleName().toString()
: sharedPreference.value();
className = name + sharedPreference.preferencesSuffix();
editorName = name + sharedPreference.editorSuffix();
implSharedPreference = sharedPreference.implSharedPreference();
multiProcess = sharedPreference.multiProcess();
JavaFileObject jfo = filer.createSourceFile(getPackageName() + "." + className);
this.mWriter = new JavaWriter(jfo.openWriter());
// set the name of the sharedPreferences created with the context
// DefaultPreferenceName defName = element.getAnnotation(DefaultPreferenceName.class);
preferencesName = sharedPreference.preferenceName();
// default type if not specified
final PreferenceType defaultPreferenceType = sharedPreference.defaultPreferenceType();
Set<String> preferenceIds = new LinkedHashSet<>();
for (Element e : element.getEnclosedElements()) {
if (!e.getKind().isField()) {
messager.printMessage(Diagnostic.Kind.WARNING, e.getSimpleName() + " is not a field", e);
continue;
}
VariableElement var = (VariableElement) e;
if (!var.asType().toString().equals("java.lang.String")) {
messager.printMessage(Diagnostic.Kind.WARNING, var.asType().toString() + " is not of type String", e);
continue;
}
if (var.getConstantValue() == null) {
messager.printMessage(Diagnostic.Kind.ERROR, var.getSimpleName() + " is not final or no value is set", e);
continue;
}
final String preferenceName = var.getSimpleName().toString();//Preference.camelCaseName(var.getSimpleName().toString());
Preference old = preferences.get(preferenceName);
if (old != null) {
messager.printMessage(Diagnostic.Kind.WARNING, preferenceName + " used here is ignored", var);
messager.printMessage(Diagnostic.Kind.WARNING, "because it was already defined here", old.getElement());
continue;
}
final String id = var.getConstantValue().toString();
if (!preferenceIds.add(id))
messager.printMessage(Diagnostic.Kind.WARNING, "preference id " + id + " is already in use");
preferences.put(preferenceName, new Preference(preferenceName, id, var, defaultPreferenceType));
}
}
public void write() throws IOException {
mWriter.setIndent(" ");
mWriter.emitPackage(getPackageName())
.emitSingleLineComment("generated code, do not modify")
.emitSingleLineComment("for more information see https://github.com/sevenshal/oksharedpref-api")
.emitEmptyLine()
.emitImports(Context.class, SharedPreferences.class)
.emitImports("android.content.SharedPreferences.Editor",
"android.content.SharedPreferences.OnSharedPreferenceChangeListener",
"cn.framework.oksharedpref.MPSPUtils")
.emitEmptyLine()
.emitImports(Set.class)
.emitEmptyLine();
if (implSharedPreference) {
mWriter.beginType(className, "class", Modifier.PUBLIC,
null, mElement.getSimpleName().toString(), "SharedPreferences");
} else {
mWriter.beginType(className, "class", Modifier.PUBLIC,
null, mElement.getSimpleName().toString());
}
mWriter.emitEmptyLine();
mWriter.emitField(className, DEFAULT_INSTANCE, Modifier.PRIVATE_STATIC, null);
mWriter.emitField("String", "PREFERENCES_NAME", Modifier.PUBLIC_FINAL_STATIC, "\"" + preferencesName + "\"")
.emitEmptyLine();
mWriter.emitField("SharedPreferences", PREFERENCES, Modifier.PRIVATE_FINAL)
.emitEmptyLine();
mWriter.emitJavadoc("single instance using '%1$s' for preferences name.\n@param %2$s the context to use"
, preferencesName, PAR_CONTEXT)
.beginMethod(className, "defaultInstance", Modifier.PUBLIC_STATIC, "Context", PAR_CONTEXT)
.beginControlFlow("if (%1$s == null)", DEFAULT_INSTANCE)
.beginControlFlow("synchronized (%1$s.class)", className)
.beginControlFlow("if (%1$s == null)", DEFAULT_INSTANCE)
.emitStatement("%1$s = new %2$s(%3$s.getApplicationContext())", DEFAULT_INSTANCE, className, PAR_CONTEXT)
.endControlFlow()
.endControlFlow()
.endControlFlow()
.emitStatement("return instance")
.endMethod()
.emitEmptyLine();
// default constructor with context using default preferences name
mWriter.emitJavadoc("constructor using '%1$s' for the preferences name.\n@param %2$s the context to use",
preferencesName, PAR_CONTEXT)
.beginConstructor(Modifier.PUBLIC, "Context", PAR_CONTEXT)
.emitStatement("this(%1$s, %2$s)",
PAR_CONTEXT, "PREFERENCES_NAME")
.endConstructor()
.emitEmptyLine();
// constructor with name for preferences
mWriter.emitJavadoc("constructor using <i>%2$s</i> for the preferences name.<br/>\n<i>It is strongly advised against using it, unless you know what you're doing.</i>\n" +
"@param %3$s the context to use\n@param %2$s the name for the preferences",
preferencesName, PAR_NAME, PAR_CONTEXT)
.beginConstructor(Modifier.PUBLIC, "Context", PAR_CONTEXT, "String", PAR_NAME)
.emitStatement(multiProcess
? "this.%1s = MPSPUtils.getSharedPref(%2s, %3s)"
: "this.%1s = %2s.getSharedPreferences(%3s, Context.MODE_PRIVATE)",
PREFERENCES, PAR_CONTEXT, PAR_NAME)
.endConstructor();
// constructor with preferences
// mWriter.emitJavadoc("constructor using the supplied SharedPreferences\n@param %1$s the SharedPreferences to use\n", "preferences")
// .beginConstructor(Modifier.PUBLIC, "SharedPreferences", "preferences")
// .emitStatement("this.%1s = preferences",
// PREFERENCES, "preferences")
// .endConstructor();
// implement SharedPreferences by just wrapping the shared preferences
if (implSharedPreference) {
wrapSharedPreferencesInterface(Modifier.PUBLIC, editorName, PREFERENCES, SharedPreferences.class.getMethods());
} else {
writeCommonMethod(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());
}
// creating accessors for the fields annotated
for (Map.Entry<String, Preference> entry : preferences.entrySet()) {
entry.getValue().writeGetter(mWriter);
entry.getValue().writeSetter(mWriter);
}
// creating nested inner class for the editor
if (implSharedPreference) {
mWriter.emitEmptyLine().beginType(editorName, "class", Modifier.PUBLIC_STATIC, null, SharedPreferences.Editor.class.getCanonicalName());
} else {
mWriter.emitEmptyLine().beginType(editorName, "class", Modifier.PUBLIC_STATIC, null);
}
mWriter.emitEmptyLine()
.emitField(SharedPreferences.Editor.class.getCanonicalName(), EDITOR, Modifier.PRIVATE_FINAL)
.emitEmptyLine();
mWriter.beginConstructor(Modifier.PUBLIC,
SharedPreferences.Editor.class.getCanonicalName(), PAR_EDITOR)
.emitStatement("this.%1$s = %2$s", EDITOR, PAR_EDITOR)
.endConstructor();
if (implSharedPreference) {
wrapEditorInterface(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());
} else {
wrapEditorApplyMethod(Modifier.PUBLIC, editorName, EDITOR, SharedPreferences.Editor.class.getMethods());
}
// creating accessors for the fields annotated
for (Map.Entry<String, Preference> entry : preferences.entrySet()) {
entry.getValue().writeChainSetter(mWriter, editorName, EDITOR);
}
mWriter.endType();
mWriter.endType();
mWriter.close();
}
private void wrapSharedPreferencesInterface(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {
for (Method method : methods) {
mWriter.emitEmptyLine().emitAnnotation(Override.class);
boolean isCustomWrapperNeeded = method.getReturnType().equals(SharedPreferences.Editor.class);
final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);
if (method.getReturnType().equals(void.class))
mWriter.emitStatement("%1$s.%2$s(%3$s)", wrappedElement, method.getName(), params);
else {
if (isCustomWrapperNeeded)
mWriter.emitStatement("return new %1$s(%2$s.%3$s(%4$s))", editor, wrappedElement, method.getName(), params);
else
mWriter.emitStatement("return %1$s.%2$s(%3$s)", wrappedElement, method.getName(), params);
}
mWriter.endMethod();
}
}
private void writeCommonMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {
// final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);
mWriter.emitEmptyLine().beginMethod(editor, "edit", modifiersPublic)
.emitStatement("return new %1$s(mPreferences.edit())", editor).endMethod();
mWriter.emitEmptyLine().beginMethod("SharedPreferences", "prefs", modifiersPublic)
.emitStatement("return this.%1$s", PREFERENCES).endMethod();
}
private void wrapEditorInterface(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {
for (Method method : methods) {
mWriter.emitEmptyLine().emitAnnotation(Override.class);
boolean isCustomWrapperNeeded = method.getReturnType().equals(SharedPreferences.Editor.class);
final String params = beginMethod(modifiersPublic, editor, method, isCustomWrapperNeeded);
if (method.getReturnType().equals(boolean.class))
mWriter.emitStatement("return %1$s.%2$s(%3$s)", wrappedElement, method.getName(), params);
else {
mWriter.emitStatement("%1$s.%2$s(%3$s)", wrappedElement, method.getName(), params);
if (!method.getReturnType().equals(void.class))
mWriter.emitStatement("return this");
}
mWriter.endMethod();
}
}
private void wrapEditorApplyMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, String wrappedElement, Method[] methods) throws IOException {
mWriter.emitEmptyLine().beginMethod("void", "apply", modifiersPublic)
.emitStatement("%1$s.apply()", wrappedElement);
mWriter.endMethod();
}
private String beginMethod(Set<javax.lang.model.element.Modifier> modifiersPublic, String editor, Method method, boolean isCustomWrapperNeeded) throws IOException {
String params = "";
final String retType = isCustomWrapperNeeded ?
editor : method.getGenericReturnType().getTypeName().replace('$', '.');
if (method.getParameterCount() > 0) {
String[] parameters = new String[method.getParameterCount() * 2];
for (int i = 0; i < method.getParameterCount(); i++) {
parameters[2 * i] = method.getGenericParameterTypes()[i].getTypeName().replace('$', '.');
parameters[2 * i + 1] = method.getParameters()[i].getName();
if (i > 0)
params += ", ";
params += parameters[2 * i + 1];
}
mWriter.beginMethod(retType, method.getName(), modifiersPublic, parameters);
} else {
mWriter.beginMethod(retType, method.getName(), modifiersPublic);
}
return params;
}
public String getPackageName() {
Element enclosingElement = mElement.getEnclosingElement();
if (enclosingElement != null && enclosingElement instanceof PackageElement) {
return ((PackageElement) enclosingElement).getQualifiedName().toString();
}
return "";
}
}
================================================
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/SharedPreferencesAnnotationProcessor.java
================================================
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 David Medenjak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cn.framework.oksharedpref.annotations.processor;
import java.io.IOException;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import cn.framework.oksharedpref.annotations.SharedPreference;
@SupportedAnnotationTypes("cn.framework.oksharedpref.annotations.SharedPreference")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class SharedPreferencesAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element e : roundEnv.getElementsAnnotatedWith(SharedPreference.class)) {
if (e.getKind().isField()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Just interfaces annotated by @SharedPreference are supported.", e);
continue;
}
if (e.getKind().isClass()) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Just interfaces annotated by @SharedPreference are supported.", e);
}
PreferenceHolder prefHolder;
try {
prefHolder = new PreferenceHolder((TypeElement) e, processingEnv.getFiler(), processingEnv.getMessager());
prefHolder.write();
} catch (IOException ex) {
ex.printStackTrace();
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ex.getMessage(), e);
}
}
return true;
}
}
================================================
FILE: processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
================================================
cn.framework.oksharedpref.annotations.processor.SharedPreferencesAnnotationProcessor
================================================
FILE: settings.gradle
================================================
include ':app', ':api', ':annotations', ':processor'
gitextract_7_weegng/ ├── .gitignore ├── README.md ├── annotations/ │ ├── .gitignore │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── cn/ │ └── framework/ │ └── oksharedpref/ │ └── annotations/ │ ├── DefaultValue.java │ ├── PreferenceType.java │ ├── SharedPreference.java │ └── Type.java ├── api/ │ ├── .gitignore │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── cn/ │ └── framework/ │ └── oksharedpref/ │ ├── MPSPUtils.java │ └── OkSharedPrefContentProvider.java ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── cn/ │ │ └── framework/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── cn/ │ │ │ └── framework/ │ │ │ └── oksharedpref/ │ │ │ └── app/ │ │ │ ├── IMsg.java │ │ │ ├── MainActivity.java │ │ │ └── SeActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ └── content_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── cn/ │ └── framework/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── processor/ │ ├── .gitignore │ ├── build.gradle │ └── src/ │ └── main/ │ ├── java/ │ │ └── cn/ │ │ └── framework/ │ │ └── mpsharedpreferences/ │ │ └── annotations/ │ │ └── processor/ │ │ ├── Modifier.java │ │ ├── Preference.java │ │ ├── PreferenceHolder.java │ │ └── SharedPreferencesAnnotationProcessor.java │ └── resources/ │ └── META-INF/ │ └── services/ │ └── javax.annotation.processing.Processor └── settings.gradle
SYMBOL INDEX (89 symbols across 12 files)
FILE: annotations/src/main/java/cn/framework/oksharedpref/annotations/PreferenceType.java
type PreferenceType (line 41) | public enum PreferenceType {
method PreferenceType (line 83) | PreferenceType(String returnType, String fullName) {
method getReturnType (line 93) | public String getReturnType() {
method getFullName (line 102) | public String getFullName() {
FILE: api/src/main/java/cn/framework/oksharedpref/MPSPUtils.java
class MPSPUtils (line 18) | public class MPSPUtils {
method isProviderProcess (line 22) | private static boolean isProviderProcess(Context ctx) {
method getSharedPref (line 49) | public static SharedPreferences getSharedPref(Context ctx, String name) {
FILE: api/src/main/java/cn/framework/oksharedpref/OkSharedPrefContentProvider.java
class OkSharedPrefContentProvider (line 25) | public class OkSharedPrefContentProvider extends ContentProvider {
method handle (line 50) | private static Bundle handle(SharedPreferences sp, Bundle extras) {
method call (line 120) | @Override
method registListener (line 131) | void registListener(SharedPreferences pref, final String name) {
method isSafeMode (line 156) | private static boolean isSafeMode(Context context) {
method getAuthorityUri (line 169) | public static Uri getAuthorityUri(Context context, String name) {
method getLastCause (line 189) | private static Throwable getLastCause(Throwable tr) {
method getSharedPreferences (line 210) | public static SharedPreferences getSharedPreferences(Context context, ...
method OkSharedPrefContentProvider (line 217) | @Deprecated
class SharedPreferencesImpl (line 222) | private static final class SharedPreferencesImpl implements SharedPref...
method SharedPreferencesImpl (line 231) | private SharedPreferencesImpl(Context context, String name, int mode) {
method getAll (line 237) | @SuppressWarnings("unchecked")
method getString (line 244) | @Override
method getStringSet (line 251) | @Override
method getInt (line 259) | @Override
method getLong (line 266) | @Override
method getFloat (line 273) | @Override
method getBoolean (line 280) | @Override
method contains (line 287) | @Override
method edit (line 292) | @Override
method registerOnSharedPreferenceChangeListener (line 297) | @Override
method unregisterOnSharedPreferenceChangeListener (line 306) | @Override
method getListeners (line 314) | private Map<OnSharedPreferenceChangeListener, ContentObserverImplHol...
class ContentObserverImplHolder (line 325) | private class ContentObserverImplHolder {
method ContentObserverImplHolder (line 328) | ContentObserverImplHolder(OnSharedPreferenceChangeListener listene...
method finalize (line 332) | @Override
class ContentObserverImpl (line 343) | private class ContentObserverImpl extends ContentObserver {
method ContentObserverImpl (line 349) | private ContentObserverImpl(OnSharedPreferenceChangeListener liste...
method destroy (line 354) | public void destroy() {
method onChange (line 366) | @Override
method call (line 377) | private Object call(String key, int type, Bundle arg) {
class EditorImpl (line 391) | public final class EditorImpl implements Editor {
method putString (line 395) | @Override
method putStringSet (line 403) | @Override
method putInt (line 411) | @Override
method putLong (line 419) | @Override
method putFloat (line 427) | @Override
method putBoolean (line 435) | @Override
method remove (line 443) | @Override
method clear (line 451) | @Override
method apply (line 460) | @Override
method commit (line 465) | @Override
method setValue (line 470) | private boolean setValue(int type) {
method wrapperSet (line 480) | private static HashSet<String> wrapperSet(Set<String> set) {
method makeAction (line 484) | private static String makeAction(String name) {
method onCreate (line 488) | @Override
method query (line 493) | @Override
method update (line 498) | @SuppressWarnings("unchecked")
method getType (line 504) | @Override
method insert (line 509) | @Override
method delete (line 514) | @Override
FILE: app/src/androidTest/java/cn/framework/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 19) | @Test
FILE: app/src/main/java/cn/framework/oksharedpref/app/IMsg.java
type IMsg (line 13) | @SharedPreference(value = "Msg", implSharedPreference = false, preferenc...
FILE: app/src/main/java/cn/framework/oksharedpref/app/MainActivity.java
class MainActivity (line 15) | public class MainActivity extends Activity implements SharedPreferences....
method onCreate (line 19) | @Override
method onSharedPreferenceChanged (line 44) | @Override
FILE: app/src/main/java/cn/framework/oksharedpref/app/SeActivity.java
class SeActivity (line 15) | public class SeActivity extends Activity implements SharedPreferences.On...
method onCreate (line 19) | @Override
method onSharedPreferenceChanged (line 36) | @Override
method onDestroy (line 44) | @Override
FILE: app/src/test/java/cn/framework/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Modifier.java
class Modifier (line 9) | class Modifier {
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Preference.java
class Preference (line 44) | public class Preference {
method camelCaseName (line 65) | public static String camelCaseName(String name) {
method Preference (line 74) | public Preference(String preferenceName, String preferenceId, Variable...
method getElement (line 101) | public VariableElement getElement() {
method writeGetter (line 105) | public void writeGetter(JavaWriter writer) throws IOException {
method writeSetter (line 121) | public void writeSetter(JavaWriter writer) throws IOException {
method writeChainSetter (line 128) | public void writeChainSetter(JavaWriter writer, String editorType, Str...
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/PreferenceHolder.java
class PreferenceHolder (line 56) | public class PreferenceHolder {
method PreferenceHolder (line 80) | public PreferenceHolder(TypeElement element, Filer filer, Messager mes...
method write (line 131) | public void write() throws IOException {
method wrapSharedPreferencesInterface (line 243) | private void wrapSharedPreferencesInterface(Set<javax.lang.model.eleme...
method writeCommonMethod (line 261) | private void writeCommonMethod(Set<javax.lang.model.element.Modifier> ...
method wrapEditorInterface (line 270) | private void wrapEditorInterface(Set<javax.lang.model.element.Modifier...
method wrapEditorApplyMethod (line 287) | private void wrapEditorApplyMethod(Set<javax.lang.model.element.Modifi...
method beginMethod (line 293) | private String beginMethod(Set<javax.lang.model.element.Modifier> modi...
method getPackageName (line 314) | public String getPackageName() {
FILE: processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/SharedPreferencesAnnotationProcessor.java
class SharedPreferencesAnnotationProcessor (line 43) | @SupportedAnnotationTypes("cn.framework.oksharedpref.annotations.SharedP...
method process (line 47) | @Override
Condensed preview — 42 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (98K chars).
[
{
"path": ".gitignore",
"chars": 86,
"preview": "*.iml\n.gradle\n/local.properties\n/.idea\n.DS_Store\n/build\n/captures\n.externalNativeBuild"
},
{
"path": "README.md",
"chars": 3080,
"preview": "# oksharedpref\n\n```\n通过注解生成SharedPreferences实现的工具。解决安卓SharedPreferences多进程数据访问不一致的问题。\n```\n\n## 简介\n1. 让你告别手写包装代码管理SharedPre"
},
{
"path": "annotations/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "annotations/build.gradle",
"chars": 5203,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/DefaultValue.java",
"chars": 2275,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/PreferenceType.java",
"chars": 2856,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/SharedPreference.java",
"chars": 3272,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "annotations/src/main/java/cn/framework/oksharedpref/annotations/Type.java",
"chars": 1987,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "api/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "api/build.gradle",
"chars": 3376,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "api/src/main/AndroidManifest.xml",
"chars": 349,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"cn."
},
{
"path": "api/src/main/java/cn/framework/oksharedpref/MPSPUtils.java",
"chars": 1949,
"preview": "package cn.framework.oksharedpref;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android"
},
{
"path": "api/src/main/java/cn/framework/oksharedpref/OkSharedPrefContentProvider.java",
"chars": 18223,
"preview": "package cn.framework.oksharedpref;\n\nimport android.content.ContentProvider;\nimport android.content.ContentResolver;\nimpo"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 1105,
"preview": "apply plugin: 'com.android.application'\n\nandroid {\n compileSdkVersion 26\n buildToolsVersion '26.0.2'\n defaultCo"
},
{
"path": "app/proguard-rules.pro",
"chars": 938,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
},
{
"path": "app/src/androidTest/java/cn/framework/ExampleInstrumentedTest.java",
"chars": 728,
"preview": "package cn.framework;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport andro"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 1068,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/cn/framework/oksharedpref/app/IMsg.java",
"chars": 975,
"preview": "package cn.framework.oksharedpref.app;\n\n\nimport cn.framework.oksharedpref.annotations.DefaultValue;\nimport cn.framework."
},
{
"path": "app/src/main/java/cn/framework/oksharedpref/app/MainActivity.java",
"chars": 1727,
"preview": "package cn.framework.oksharedpref.app;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.conte"
},
{
"path": "app/src/main/java/cn/framework/oksharedpref/app/SeActivity.java",
"chars": 1549,
"preview": "package cn.framework.oksharedpref.app;\n\nimport android.app.Activity;\nimport android.content.SharedPreferences;\nimport an"
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 392,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app/src/main/res/layout/content_main.xml",
"chars": 354,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 208,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#3F51B5</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/dimens.xml",
"chars": 67,
"preview": "<resources>\n <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 137,
"preview": "<resources>\n <string name=\"app_name\">MultiProcessSharepref</string>\n <string name=\"action_settings\">Settings</stri"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 412,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"android:Theme\">\n <!-- Custom"
},
{
"path": "app/src/test/java/cn/framework/ExampleUnitTest.java",
"chars": 390,
"preview": "package cn.framework;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which "
},
{
"path": "build.gradle",
"chars": 690,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n r"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 230,
"preview": "#Wed Nov 01 14:56:37 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 730,
"preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "processor/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "processor/build.gradle",
"chars": 2050,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Modifier.java",
"chars": 1526,
"preview": "package cn.framework.oksharedpref.annotations.processor;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\n/**\n * "
},
{
"path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/Preference.java",
"chars": 5971,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/PreferenceHolder.java",
"chars": 16064,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "processor/src/main/java/cn/framework/mpsharedpreferences/annotations/processor/SharedPreferencesAnnotationProcessor.java",
"chars": 3026,
"preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2015 David Medenjak\n *\n * Permission is hereby granted, free of charge, "
},
{
"path": "processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
"chars": 84,
"preview": "cn.framework.oksharedpref.annotations.processor.SharedPreferencesAnnotationProcessor"
},
{
"path": "settings.gradle",
"chars": 53,
"preview": "include ':app', ':api', ':annotations', ':processor'\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the sevenshal/oksharedprefs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 42 files (88.3 KB), approximately 21.4k tokens, and a symbol index with 89 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.