PreferenceActivity: save value as integer - android

Using a simple EditTextPreference in my preferences activity:
<EditTextPreference
android:key="SomeKey"
android:title="#string/some_title"
android:summary="..."
android:numeric="integer"
android:maxLength="2"
/>
Is there a way that this configuration value would be saved as integer? Seems now it just allows to enter numbers, but the value is still saved as string:
Calling:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
int value = preferences.getInt("SomeKey", -1);
throws me java.lang.ClassCastException: java.lang.String, and:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String value = preferences.getString("SomeKey", "-1");
retrieves the value successfully.
How to make PreferenceActivity to save value as integer by default?

You could extend EditTextPreference:
public class IntEditTextPreference extends EditTextPreference {
public IntEditTextPreference(Context context) {
super(context);
}
public IntEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IntEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected String getPersistedString(String defaultReturnValue) {
return String.valueOf(getPersistedInt(-1));
}
#Override
protected boolean persistString(String value) {
return persistInt(Integer.valueOf(value));
}
}
It would be better to overwrite onSetInitialValue() and setText() methods, but then you would have to copy some code from a base class. Above solution is simplier, but it's quite tricky - "string" methods do something with ints. Try to not extend this class further ;-)
You could use it from XML by:
<package.name.IntEditTextPreference
android:key="SomeKey"
android:title="#string/some_title"
android:summary="..."
android:numeric="integer"
android:maxLength="2"
/>

Even if you set android:numeric="integer" it'll be text preference - as its name suggest. You could easily convert string value to int using Integer.valueOf(). Also you could overwrite PreferenceActivity to do conversion automatically on exit.
I think the best solution is to write simple method to get this value from preferences. Something like:
public static int getSomePref(Context context) {
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(context);
String value = prefs.getString("SomeKey", null);
return value == null ? -1 : Integer.valueOf(value);
}
Then you could very easily use it from your code.

Even though an Answer has been parked accepted I would like to share one more shorter way to achieve this :
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
int value = Integer.parseInt(preferences.getString("SomeKey", "-1"));
Since you have already set that only numbers can be entered this won't through any exception.
yet to complete my answer :
<EditTextPref
android:key="SomeKey"
android:title="#string/some_title"
android:summary="..."
android:numeric="integer"
android:maxLength="2" />

I know this is an old question with an already accepted answer but I think my solution can be helpful for someone searching for a more complete answer. I have just improved #broot answer a litte and there goes my solution:
Override the EditTextPreference to provide text to int conversion:
public class IntEditTextPreference extends EditTextPreference implements EditTextPreference.OnBindEditTextListener {
private String mText;
public IntEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setOnBindEditTextListener(this);
}
public IntEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOnBindEditTextListener(this);
}
public IntEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setOnBindEditTextListener(this);
}
public IntEditTextPreference(Context context) {
super(context);
setOnBindEditTextListener(this);
}
/**
* Saves the text to the current data storage.
*
* #param text The text to save
*/
public void setText(String text) {
final boolean wasBlocking = shouldDisableDependents();
mText = text;
int value = Integer.parseInt(text);
persistInt(value);
final boolean isBlocking = shouldDisableDependents();
if (isBlocking != wasBlocking) {
notifyDependencyChange(isBlocking);
}
notifyChanged();
}
/**
* Gets the text from the current data storage.
*
* #return The current preference value
*/
public String getText() {
return mText;
}
#Override
protected void onSetInitialValue(Object defaultValue) {
int value;
if (defaultValue != null) {
String strDefaultValue = (String) defaultValue;
int defaultIntValue = Integer.parseInt(strDefaultValue);
value = getPersistedInt(defaultIntValue);
} else {
value = getPersistedInt(0);
}
setText(Integer.toString(value));
}
#Override
public boolean shouldDisableDependents() {
return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
}
#Override
public void onBindEditText(#NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
In the preferences xml:
<your.package.here.IntEditTextPreference
android:key="some_key"
android:title="#string/some_title"
android:defaultValue="5"
app:useSimpleSummaryProvider="true"/>
Note: Don't use android:numeric nor android:inputType. Since EditTextPreference is not an EditText itself setting those attributes will do nothing. In order to achieve the desired effect on the EditText from the Dialog opened by the EditTextPreference, just set the input type in your custom EditTextPreference by implementing EditTextPreference.OnBindEditTextListener as you can see in the code above.
That's what worked for me.

I had the same Problem. (I wanted SharedPreference to give me a port number that i stored in a preferences xml file as defaultValue).
Implementing all the SharedPreferences methods would be much effort, so writing a custom method in the class that instanced the SharedPreferences, as broot suggested would be best i think.
You can aswell just use the Static method of Integer in the line where you need it:
int number = Integer.valueOf(settings.getString("myNumberString", "0"));

I think this is the shortest one I could come up with:
int CheckInterval = Integer.parseInt(sharedPreferences.getString("check_frequency","60"));

Related

Custom Text View and setText

I want to create a custom Text View and set its text by applying some function to the passed value.
For example if my xml is:-
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="#dimen/margin_raptor_medium"
android:text="someText"/>
then I would want to take the someText; apply my transformation function to it and set the Text again. basically this will be my string Id for which I will fetch the translation from my function.
EDIT:-
so In my custom view class, I am overriding the set Text Method like this:-
#Inject
StringRepository stringRepository
#Override
public void setText(CharSequence text, BufferType type) {
System.out.println("In SetTExt Method");
// modify text here
System.out.println("The text that is set here is:" + text);
String modifiedText = StringRepository.getString((String)text);
super.setText(modifiedText, type);
}
Now the getString Method is giving a Null pointer exception as the map that it accesses is not getting updated.
I am updating this map during Login Time.
Extend TextView class first and then override setText() method, where you can do all the transformations. Thats it.
It should look something like this:
class YouTextView extends TextView {
public YouTextView(Context context) {
super(context);
}
public YouTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public YouTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setText(CharSequence text, BufferType type) {
// modify text here
super.setText(modifiedText, type);
}
}

overriding edtitext's getText() method causes stackoverflow, why?

i am subclassing TextInputEditText so that i can add a string to a password editText field. here is the subclass:
public class CustomInputEditTextWithPrefix extends TextInputEditText {
public CustomInputEditTextWithPrefix(Context context) {
super(context);
}
public CustomInputEditTextWithPrefix(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomInputEditTextWithPrefix(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public Editable getText() {
Editable s = (Editable) super.getText(); //why is this causing infinite stackoverflow ?
if(s!=null && s.length()>0) {
//salt the password
Editable pwSalt = new SpannableStringBuilder("my secret string");
s= pwSalt.append(s);
}
return s;
}
}
and the imlementation in xml is:
<com.myapp.ui.auth.ui.customviews.CustomInputEditTextWithPrefix
android:id="#+id/password"
android:inputType="textPassword" />
my issue is that when i execute the code the getText() override method keeps getting called over and over again. i took out the inputType but its still being called until stackoverflow. my idea was to append to the front of every string in the TextInputEditText a secret hash. What am i doing wrong ?
Maybe if you skip to assign a new value of s everything will be OK
#Override
public Editable getText() {
Editable s = (Editable) super.getText();
if(s!=null && s.length()>0) {
//salt the password
return new SpannableStringBuilder("my secret string").append(s.toString());
}
return s;
}

PersistInt slowing down button response in custom preference

I've created a custom preference that embeds two buttons (here I have subclassed Button as FastButton). The problem is executing the persistInt to store the preference drastically slows down the response of the button.
I had the notion of only executing the persistInt when the preference's lifecycle is ended, but could not find an appropriate method to override (i.e. there is nothing like onPause() for the Preference class).
I was also unsuccessful at trying to use AsyncTask to move the persistInt off of the UI thread.
Any suggestions about how I should go about mitigating the effect of persistInt on my UI response?
public final class StepperPreference extends Preference {
public int mCurrentValue = 1;
public int maxValue = Integer.MAX_VALUE;
public int minValue = Integer.MIN_VALUE;
private TextView mText;
private FastButton plusButton;
private FastButton minusButton;
public StepperPreference(Context context) {
super(context);
}
public StepperPreference(Context context, AttributeSet attrs) {
super(context, attrs);
parseCustomAttributes(attrs);
}
public StepperPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseCustomAttributes(attrs);
}
public void setmCurrentValue(int value) {
if (mCurrentValue != value) {
mCurrentValue = value;
persistInt(mCurrentValue);
}
}
private void parseCustomAttributes(AttributeSet attrs) {
int maxValueAttrInt=Integer.MAX_VALUE;
int minValueAttrInt=Integer.MIN_VALUE;
if (attrs!=null) {
TypedArray a=getContext()
.obtainStyledAttributes(attrs,
R.styleable.StepperPreference,
0, 0);
maxValueAttrInt = a.getInt(R.styleable.StepperPreference_maxValue, Integer.MAX_VALUE);
minValueAttrInt = a.getInt(R.styleable.StepperPreference_minValue, Integer.MIN_VALUE);
a.recycle();
}
if (maxValueAttrInt > minValueAttrInt) {
maxValue = maxValueAttrInt;
minValue = minValueAttrInt;
}
}
#Override
protected View onCreateView(ViewGroup parent) {
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = (View) li.inflate(R.layout.stepper_preference, parent, false);
mText = (TextView) view.findViewById(R.id.text_view);
Context context = getContext();
int localDefaultValue = 0;
mCurrentValue = getPersistedInt(localDefaultValue);
mText.setText(Integer.toString(mCurrentValue));
plusButton = (FastButton) view.findViewById(R.id.plus_button);
plusButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mCurrentValue < maxValue) {
mCurrentValue++;
mText.setText(Integer.toString(mCurrentValue));
persistInt(mCurrentValue);
}
}
});
minusButton = (FastButton) view.findViewById(R.id.minus_button);
minusButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mCurrentValue > minValue) {
mCurrentValue--;
mText.setText(Integer.toString(mCurrentValue));
persistInt(mCurrentValue);
}
}
});
return view;
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
int localDefaultValue = 0;
Object result = a.getInt(index, localDefaultValue);
return result;
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
int localDefaultValue = 0;
setmCurrentValue(restoreValue ? this.getPersistedInt(localDefaultValue) : (int) defaultValue);
}
}
CheckBoxPreference, via its TwoStatePreference superclass, uses persistBoolean() for saving the preference value, much as you are using persistInt(). I do not perceive significant latency in the processing of the CheckBox. This means one of two things:
I'm a troglodyte and am incapable of seeing obvious delays in animations and such
CheckBoxPreference does not exhibit the problems that you are seeing in your StepperPreference
note: these two possibilities are not mutually exclusive
If we assume #2 to be correct, then there's something else afoot. Method tracing, to see where you are spending time "downstream" from persistInt(), may prove useful for determining what is different about StepperPreference.
From your comment, you had a listener responding to preference changes, and that was what was causing the sluggish response. "Inline" preferences, like CheckBoxPreference and StepperPreference, will be somewhat more "twitchy" than DialogPreference subclasses like ListPreference, simply because it takes less work to change the preference state (e.g., one screen tap versus 2+). As a result, listeners need to be cheaper. For example, you might hold off on doing significant work until the user has left the PreferenceFragment and so you know that the preference values are likely to be stable for at least a second or so.

Process the value of preference before save in Android?

I need to crypt my password before save it to local android database. Everything work fine without encryption, I have preferences.xml and so. How can I call a function after I change value of preference (for example, password) ? Here is my code:
public class Preferences extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
// Get the custom preference
Preference customPref = (Preference) findPreference("pass");
customPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener(){
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String crypto = SimpleCrypto.encrypt("MYSECRETKEY", newValue.toString()); // encrypt
// Here is where I'm wrong, I guess.
SharedPreferences settings = getSharedPreferences("preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString("pass", crypto);
editor.commit();
});
}
}
P.S: Like this, when I change password, it stores password without encryption.
I did this by extending the base EditTextPreference and encrypting/decrypting the password there:
public class EncryptedEditTextPreference extends EditTextPreference {
public EncryptedEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EncryptedEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EncryptedEditTextPreference(Context context) {
super(context);
}
#Override
public String getText() {
String value = super.getText();
return SecurityUtils.decrypt(value);
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
super.setText(restoreValue ? getPersistedString(null) : (String) defaultValue);
}
#Override
public void setText(String text) {
if (Utils.isStringBlank(text)) {
super.setText(null);
return;
}
super.setText(SecurityUtils.encrypt(text));
}
}
There are some calls to my personal utilities, but I think the code is pretty clear in what you need to do.

Android TimePicker in PreferenceScreen -> read the values

I have a custom DialogPreference. The Dialog is called from a PreferenceScreen.
All works fine, the Dialog starts and shows the TimePicker.
But how do I get the selected values?
First of all, I tried to write the selected hours in the summary of the Preference. (therefore the var xxx :)
Later on, I want to save the values in SharedPreferences.
This is what I have for now:
public class Calendar extends DialogPreference implements
TimePicker.OnTimeChangedListener {
TimePicker tp;
int xxx;
public Calendar(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public Calendar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
private void initialize() {
setPersistent(true);
}
#Override
protected View onCreateDialogView() {
tp = new TimePicker(getContext());
tp.setIs24HourView(true);
return tp;
}
#Override
public void onTimeChanged(TimePicker arg0, int arg1, int arg2) {
}
#Override
public void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
// getEditor().
setTitle(getTitle());
setSummary(Integer.toString(xxx));
}
}
private TimePicker.OnTimeChangedListener mTimeSetListener =
new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
xxx=hourOfDay;
}
};
}
Thanks a lot and best regards
Thanks for asking this question, it provided me with an important answer on how to create a DialogPreference.
I hope I might also have an answer for you. I modified your code a little bit and I can now store the time selected from the Dialog:
#Override
protected View onCreateDialogView() {
this.tp = new TimePicker(getContext());
this.tp.setIs24HourView(true);
final String storedValue = getPersistedString("07:00");
final String[] split = storedValue.split(":");
this.tp.setCurrentHour(Integer.parseInt(split[0]));
this.tp.setCurrentMinute(Integer.parseInt(split[1]));
return this.tp;
}
#Override
public void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
final String result = this.tp.getCurrentHour() + ":" + this.tp.getCurrentMinute();
persistString(result);
}
}
When the dialog is shown I retrieve the stored value and simply set the currentHour and currentMinute fields of the TimePicker. The other way round when the dialog is closed. Since I control both the format on the way in as well as on the way out there should not be a problem with illegal values.
Was this what you were looking for?
To store the value in shared pref, implement on preference Change Listener.
note that preference should be default Shared preference
preferences = PreferenceManager.getDefaultSharedPreferences(context);
editor = preferences.edit();
inside onprefchange:
if (preference.getKey().equals(getString(R.string.reminder_end_time_key))){
editor.putString("End_Date", String.valueOf(newValue));
editor.apply();
endTimePickerPreference.setSummary((CharSequence)newValue);
}

Categories

Resources