Skip to content
This repository has been archived by the owner on Feb 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #962 from WonderCsabo/264_sharedpref_string_set
Browse files Browse the repository at this point in the history
SharefPref StringSet implementation
  • Loading branch information
DayS committed Jun 9, 2014
2 parents 8bcb94b + 311e6e9 commit ccf9742
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 22 deletions.
@@ -0,0 +1,49 @@
/**
* Copyright (C) 2010-2014 eBusiness Information, Excilys Group
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed To in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.androidannotations.annotations.sharedpreferences;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.androidannotations.annotations.ResId;

/**
* Use on methods in {@link SharedPref} annotated class. The generated method
* will return an empty {@link java.util.Set} of Strings by default.
* <p/>
* The key of the preference will be the method name by default. This can be
* overridden by specifying a string resource with the {@link #keyRes()}
* parameter.
* <p/>
* <b>Implementation note:</b>
* <p/>
* Since {@code SharedPreferences.getStringSet} is only available from API 11,
* the generated method serializes the {@code Set<String>} into a {@code String}
* , and persists it with
* {@link android.content.SharedPreferences.Editor#putString(String, String)
* SharedPreferences.Editor#putString(String, String)} using API 10 and below.
* From API 11 and up, the generated method simply uses the native
* {@link android.content.SharedPreferences SharedPreferences}
* {@code Set<String>} methods.
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface DefaultStringSet {

int keyRes() default ResId.DEFAULT_VALUE;
}
Expand Up @@ -47,6 +47,10 @@ protected StringPrefEditorField<T> stringField(String key) {
return new StringPrefEditorField<T>(cast(), key);
}

protected StringSetPrefEditorField<T> stringSetField(String key) {
return new StringSetPrefEditorField<T>(cast(), key);
}

protected BooleanPrefEditorField<T> booleanField(String key) {
return new BooleanPrefEditorField<T>(cast(), key);
}
Expand Down
@@ -0,0 +1,103 @@
/**
* Copyright (C) 2010-2014 eBusiness Information, Excilys Group
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed To in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.androidannotations.api.sharedpreferences;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import android.util.Log;
import android.util.Xml;

public final class SetXmlSerializer {

private static final String NAMESPACE = "";
private static final String STRING_TAG = "AA_string";
private static final String SET_TAG = "AA_set";

private SetXmlSerializer() {

}

public static String serialize(Set<String> set) {
if (set == null) {
set = Collections.emptySet();
}

StringWriter writer = new StringWriter();
XmlSerializer serializer = Xml.newSerializer();

try {
serializer.setOutput(writer);
serializer.startTag(NAMESPACE, SET_TAG);

for (String string : set) {
serializer.startTag(NAMESPACE, STRING_TAG) //
.text(string) //
.endTag(NAMESPACE, STRING_TAG);
}

serializer.endTag(NAMESPACE, SET_TAG) //
.endDocument();

} catch (IllegalArgumentException e) {

} catch (IllegalStateException e) {

} catch (IOException e) {

}

return writer.toString();
}

public static Set<String> deserialize(String data) {
Set<String> stringSet = new TreeSet<String>();
XmlPullParser parser = Xml.newPullParser();

try {
parser.setInput(new StringReader(data));
parser.next();
parser.require(XmlPullParser.START_TAG, NAMESPACE, SET_TAG);

while (parser.next() != XmlPullParser.END_TAG) {
parser.require(XmlPullParser.START_TAG, NAMESPACE, STRING_TAG);

parser.next();
parser.require(XmlPullParser.TEXT, null, null);
stringSet.add(parser.getText());

parser.next();
parser.require(XmlPullParser.END_TAG, null, STRING_TAG);
}
} catch (XmlPullParserException e) {
Log.w("getStringSet", e);
return null;
} catch (IOException e) {
Log.w("getStringSet", e);
return null;
}

return stringSet;
}
}
Expand Up @@ -17,42 +17,74 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

/**
* Reflection utils to call SharedPreferences$Editor.apply when possible,
* falling back to commit when apply isn't available.
* Reflection utils to call most efficient methods of SharedPreferences and
* SharedPreferences$Editor or fall back to another implementations.
*/
public abstract class SharedPreferencesCompat {

private SharedPreferencesCompat() {
}

private static final Method sApplyMethod = findApplyMethod();
private static final Method sApplyMethod = findMethod(SharedPreferences.Editor.class, "apply");
private static final Method sGetStringSetMethod = findMethod(SharedPreferences.class, "getStringSet", String.class, Set.class);
private static final Method sPutStringSetMethod = findMethod(SharedPreferences.Editor.class, "putStringSet", String.class, Set.class);

private static Method findApplyMethod() {
public static void apply(SharedPreferences.Editor editor) {
try {
invoke(sApplyMethod, editor);
return;
} catch (NoSuchMethodException e) {
editor.commit();
}
}

public static Set<String> getStringSet(SharedPreferences preferences, String key, Set<String> defValues) {
try {
Class<Editor> cls = SharedPreferences.Editor.class;
return cls.getMethod("apply");
return invoke(sGetStringSetMethod, preferences, key, defValues);
} catch (NoSuchMethodException e) {
String serializedSet = preferences.getString(key, null);
return SetXmlSerializer.deserialize(serializedSet);
}
}

public static void putStringSet(SharedPreferences.Editor editor, String key, Set<String> values) {
try {
invoke(sPutStringSetMethod, editor, key, values);
} catch (NoSuchMethodException e1) {
editor.putString(key, SetXmlSerializer.serialize(values));
}
}

private static Method findMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
try {
return clazz.getMethod(name, parameterTypes);
} catch (NoSuchMethodException unused) {
// fall through
}
return null;
}

public static void apply(SharedPreferences.Editor editor) {
if (sApplyMethod != null) {
try {
sApplyMethod.invoke(editor);
return;
} catch (InvocationTargetException unused) {
// fall through
} catch (IllegalAccessException unused) {
// fall through
}
@SuppressWarnings("unchecked")
public static <T> T invoke(Method method, Object obj, Object... args) throws NoSuchMethodException {
if (method == null) {
throw new NoSuchMethodException();
}

try {
return (T) method.invoke(obj, args);
} catch (IllegalAccessException e) {
// fall through
} catch (IllegalArgumentException e) {
// fall through
} catch (InvocationTargetException e) {
// fall through
}
editor.commit();

throw new NoSuchMethodException(method.getName());
}
}
Expand Up @@ -15,6 +15,8 @@
*/
package org.androidannotations.api.sharedpreferences;

import java.util.Set;

import android.content.SharedPreferences;

public abstract class SharedPreferencesHelper {
Expand All @@ -41,6 +43,10 @@ protected StringPrefField stringField(String key, String defaultValue) {
return new StringPrefField(sharedPreferences, key, defaultValue);
}

protected StringSetPrefField stringSetField(String key, Set<String> defaultValue) {
return new StringSetPrefField(sharedPreferences, key, defaultValue);
}

protected BooleanPrefField booleanField(String key, boolean defaultValue) {
return new BooleanPrefField(sharedPreferences, key, defaultValue);
}
Expand Down
@@ -0,0 +1,30 @@
/**
* Copyright (C) 2010-2014 eBusiness Information, Excilys Group
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed To in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.androidannotations.api.sharedpreferences;

import java.util.Set;

public final class StringSetPrefEditorField<T extends EditorHelper<T>> extends AbstractPrefEditorField<T> {

StringSetPrefEditorField(T editorHelper, String key) {
super(editorHelper, key);
}

public T put(Set<String> value) {
SharedPreferencesCompat.putStringSet(editorHelper.getEditor(), key, value);
return editorHelper;
}
}
@@ -0,0 +1,44 @@
/**
* Copyright (C) 2010-2014 eBusiness Information, Excilys Group
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed To in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.androidannotations.api.sharedpreferences;

import java.util.Set;

import android.content.SharedPreferences;

public final class StringSetPrefField extends AbstractPrefField {

private final Set<String> defaultValue;

StringSetPrefField(SharedPreferences sharedPreferences, String key, Set<String> defaultValue) {
super(sharedPreferences, key);
this.defaultValue = defaultValue;
}

public Set<String> get() {
return getOr(defaultValue);
}

public Set<String> getOr(Set<String> defaultValue) {
return SharedPreferencesCompat.getStringSet(sharedPreferences, key, defaultValue);
}

public void put(Set<String> value) {
SharedPreferences.Editor editor = sharedPreferences.edit();
SharedPreferencesCompat.putStringSet(editor, key, value);
apply(editor);
}
}

0 comments on commit ccf9742

Please sign in to comment.