Custom EditTextPreference. How and when to get text for saving purposes - android

I'm writing custom EditTextPreference.
Using this code inside my CustomEditTextPreference:
#Override
protected void onDialogClosed(boolean shouldSave) {
if (shouldSave) {
String sValue = getText();
value = Float.parseFloat(sValue);
peristValue();
}
}
sValue is null. How do I acquire the value from edit then?

You should probably use
getEditText().getText().toString();
Since getText() by itself gets the current SharedPreference value, which may or may not exist.

Related

Cannot read country code selected in a spinner Android

I am working on an app in which users have to select a country code, i was successful in creating a spinner for the said purpose as shown in this link:
Creating a spinner for choosing country code
But i am getting problem in reading the value selected in the spinner.
{
String abc = onCountryPickerClick();//abc is always null
}
public String onCountryPickerClick (){
ccp.setOnCountryChangeListener(new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
}
});
return selected_country_code;
}
When String abc = onCountryPickerClick(); is being invoked, the selected_country_code value will be assigned to abc.
When your CountryCodePicker.OnCountryChangeListener's onCountrySelected() method is being invoked, the ccp.getSelectedCountryCodeWithPlus();'s value gets assigned to selected_country_code. Since String is immutable, changing selected_country_code's value won't change the value of abc, nor the return selected_country_code; will be invoked.
One of possible solutions would be to change your CountryCodePicker.OnCountryChangeListener anonymous implementation to assign the selected country value to abc e.g.
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
abc = selected_country_code
}
Callbacks are not synchronous. Unfortunately, you cannot simply do String abc = onCountryPickerClick(); because what you are returning is something that is not yet set. Let's go through your code:
ccp.setOnCountryChangeListener(
new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
selected_country_code = ccp.getSelectedCountryCodeWithPlus();
}
});
The code seems to say that when the country is selected in the spinner, you assign the value of selected_country_code. Assuming this is an action triggered by the user, when you call String abc = onCountryPickerClick();, how can you be sure the user has selected anything? This is the issue. You cannot be sure that the user has already selected the option and returning the value is not enough.
You can solve this in many ways. You can for example keep propagating the callback:
public void onCountryPickerClick(OnCountryChangeListener listener){
ccp.setOnCountryChangeListener(listener);
}
// Anywhere you call this
onCountryPickerClick(new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
// Here do whatever you want with the selected country
}
});
The above approach is not very different than what you have now. There are other options. You could use java observables i.e.:
class CountryCodeObservable extends Observable {
private String value;
public CountryCodeObservable(String value) {
this.value = value;
}
public void setCountryCode(String countryCode) {
value = countryCode;
setChanged();
notifyObservers(value);
}
}
public CountryCodeObservable onCountryPickerClick(){
CountryCodeObservable retValue = new CountryCodeObservable("");
ccp.setOnCountryChangeListener(
new CountryCodePicker.OnCountryChangeListener() {
#Override
public void onCountrySelected() {
retValue.setCountryCode(ccp.getSelectedCountryCodeWithPlus());
}
});
return retValue;
}
// Then when calling this method you can do something like:
CountryCodeObservable observable = onCountryPickerClick();
observable.addObserver((obj, arg) -> {
// arg is the value that changed. You'll probably need to cast it to
// a string
});
The above example lets you add more than one observable. It might be too much for your use case, I just thought it illustrates another approach and also the asynchronicity of this situation.
Again, there are even more ways to solve this, the key is that you can't simply return a string and hope it changes when the user selects anything.

Whats make value of variable become empty or back to initialization value in lifecycle

I just curious what makes a value inside of some variable become empty again or back to its initial value in the android life cycle.
First lets take a look at how i create a variable :
public class myData {
public static String myCode = "";
public static String getData(String Choice) {
String theData = "";
if ("Code".equals(Choice) {
theData = myCode;
}
return myCode;
}
public static void setData(String setData,String Choice) {
if ("Code".equals(Choice) {
myData.myCode = setData;
}
}
}
If I want to fill the variable, i usually do this :
myData.setData("value of variable","Code");
And if I want to get the value of the variable, I usually do this :
myData.getData("Code");
I just want to know what makes my variable gone inside of android lifecycle, of course excluding when the application is closed.
I have to try to Log and show the value in onstart , oncreate, onresume and onrestart. And all of them is still have the value inside of my variable intact without any problem.
My client always tells me that my application sometimes gets crash when they open some activity. I also ask if they did something while using my application,
some of them answer that the application get crashed after they got a phone call and when the phone call is ended, the application is started with a crash.
some of them also said that when they open the application and then idle the phone withouth closing the application until the phone become black screen, and when they open it again the application get crashed.
After I check the log, the problem was the variable become empty. which is why I want to know is there another possibilites that makes the value inside of the variable become empty?
As John Lord saying, on low-end device variables might back to its initial value again if there is not enough memory.
So for future reference, I use a shared preference to counter it, here is my structure for fetching the data :
public class myActivity extends AppCompatActivity {
String myCode = "";
protected void onCreate(Bundle savedInstanceState) {
....
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
....
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
}
}
And here is how i set the data :
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData",Context.MODE_PRIVATE);
sharedPreferences.edit().putString("Code","Hello World").apply();
I hope it will be helpful for those who want to search the same thing

Android preferences adding unwanted chars

I have a big problem with the SharedPreferences in Android. The preferences are adding unwanted chars to one of my string values once the application is closed. Actually it is a configurable escape sequence.
I have a simple setup, a MainActivity containing
#Override
protected void onStart() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
sequence = prefs.getString("escape_sequence", "");
}
And a preferences screen where the value is set. When i open the app go to the prefences screen, set the value correctly to \n\n and go back to the MainActivity the breakpoint is correctly displaying the sequence as Java.lang.String, value(char[2])= "\n\n", count=2. When i am now restarting the app through android studio the same breakpoint in the code suddenly displays: Java.lang.String, value(char[6])= "\n\n ", count=6, containing 4 Space and 10 escape \u0000 characters.
Can anybody why this is happening and what i can do about that?
BTW i'm not touching the SharedPreferences.Editor anywhere in the App so far. I is strictly done via the PreferencesScreen. So no overwrite is done anywhere in the app. The default values shouldn't be applied either, however the setting is android:defaultValue="\n\n" anyway.
EDIT:
I found the reason: android adds the spaces if a newline is at the end of the preference. I have no idea why.
EDIT:
Here is the custom preference code:
public class SequencePreference extends DialogPreference {
EditText sequenceInput;
public SequencePreference(Context context, AttributeSet attrs) {
super(context, attrs);
setDialogLayoutResource(R.layout.dialog_preference_sequence);
setPositiveButtonText(R.string.settings_sequence_ok);
setNegativeButtonText(R.string.settings_sequence_cancel);
setDialogIcon(null);
}
#Override
protected View onCreateDialogView() {
View view = super.onCreateDialogView();
sequenceInput= (EditText)view.findViewById(R.id.sequence_input);
return view;
}
#Override
protected void onDialogClosed(boolean positiveResult) {
// When the user selects "OK", persist the new value
if (positiveResult) {
String sequenceValue = new String( sequenceInput.getText().toString() );
String[] parts = sequenceValue.split("-");
if(parts.length == 2) {
persistString(parts[1]);
}
}
}
}
I think this is a bug in Android API 18 and newer where extra whitespace is injected when a SharedPreferences string ends with \n. For more information, see:
https://code.google.com/p/android/issues/detail?id=159799#c6
https://code.google.com/p/android/issues/detail?id=159799#c7
after you retrieve the saved string, place a trim().
example
String sequence2 = sequence.trim()

RxAndroid Update Field/Textview when String Value Changes

I am just getting started with RxJava/RxAndroid and I was wondering if I can use it to solve the following problem. Basically, given a Field, say a textview, and a value, a string, I am looking for a way to automatically update the textview whenever the value of the string changes. I am not sure exactly how I would implement this as an Observable. Let me demonstrate;
String str = "Test"; //the string value
TextView textView = (TextView) findViewById(R.id.textView); //the textview
Observable o = //looking for this part. Want to observe the String str
o.subscribe(new Observer<String>() { //subscribe here looking for string changes
#Override
public void onCompleted() {
System.out.println("Completed");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
textView.setText(s); //update the textview here
}
});
//here is where the string changes, it could be hardcoded, user input, or
//anything else really, I just want the textview to be updated automatically
//without another setText
str = "Different String";
Is what I am looking for possible with RxAndroid/RxJava?
The easiest way to accomplish that would be to use any kind of of Subject, maybe either a BehaviorSubject or a PublishSubject. A Subject is both a Subscriber (so you can put values into it with onNext) and an Observable (so you can subscribe to it). Look here for an explanation of the differences: http://reactivex.io/documentation/subject.html
So, instead of
String str = "Test";
you would have
BehaviorSubject<String> stringSubject = BehaviorSubject.<String>create("Test");
You can then directly subscribe to stringObservable.
And instead of assigning a new value to your variable like this:
str = "Hello World!";
you would do
stringSubject.onNext("Hello World!");
Oh, and never leave onError empty - doing so will quietly swallow any exceptions that may have occured earlier, and you will sit and wonder why nothing is happening. At least write e.printStacktrace().

Number Preferences in Preference Activity in Android

What I want to do is I am working on a game of life program. I want to take the time delay and make it a preference, but I want to make it available for people to type in a specific time. The number can be in miliseconds or seconds.
However I'm a little stuck on how to proceed, I haven't been able to find a simple preference that already handles this, but there might be one. Is there an easy way to make this preference and confirm that the entered data is an integer or afloat?
Use an EditTextPreference and set the input type to TYPE_CLASS_NUMBER. This will force the user to enter numbers and not letters.
EditTextPreference pref = (EditTextPreference)findPreference("preference_name");
pref.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER);
You can also enforce it with the xml attribute android:numeric. The possible relevant values for this attribute are decimal and integer.
You can also do this directly in your preferences.xml. Something like this would work:
<EditTextPreference
android:defaultValue="100"
android:dialogTitle="#string/pref_query_limit"
android:inputType="number"
android:key="pref_query_limit"
android:summary="#string/pref_query_limit_summ"
android:title="#string/pref_query_limit" />
If you are using a PreferenceActivity which you probably are, there is not one available.
You will need to do something like this:
/**
* Checks that a preference is a valid numerical value
*/
Preference.OnPreferenceChangeListener numberCheckListener = new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//Check that the string is an integer.
return numberCheck(newValue);
}
};
private boolean numberCheck(Object newValue) {
if( !newValue.toString().equals("") && newValue.toString().matches("\\d*") ) {
return true;
}
else {
Toast.makeText(ActivityUserPreferences.this, newValue+" "+getResources().getString(R.string.is_an_invalid_number), Toast.LENGTH_SHORT).show();
return false;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get XML preferences
addPreferencesFromResource(R.xml.user_preferences);
//get a handle on preferences that require validation
delayPreference = getPreferenceScreen().findPreference("pref_delay");
//Validate numbers only
delayPreference.setOnPreferenceChangeListener(numberCheckListener);
}
In Android Jetpack Preference things changed, to access EditText you have to access like this
val preference = findPreference<EditTextPreference>(getString(R.string.pref_numdefault_key))
preference?.setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_NUMBER
}

Categories

Resources