I have a spinner that have 3 values populated from array-list.
I want to save the spinner selected value to shared preferences so it can be loaded back again when the use comes back to the app. What is the correct way to do this (to avoid future problems)
1- Save position of the selection
2- Save the text of the selection
3- Get the position/text of the selection, get the corresponding enum, and save the enum name.
I am leaning towards the 3rd option incase the positions/texts changed in later updates but I am wondering what is the correct way of doing such task
Thank you
Save position (1 variant) and text (2 variant) are bad practice. Because text for your spinner items may will change in the future and their position can be changed.
I think, that you need to create enum or #TypeDef element and save it to sharedPreferences. #TypeDef is more performance but enum is more functionality (if you use Kotlin you can use sealed classes). For this solution just write mapper that can map enum to spinner item.
If you use enum, the best way is to save it name ENUM.name().
Read carefully and understand. Get the post and use at your own understanding.
Declare your spinner and sharedPreferences
public Spinner crimeType;
SharedPreferences sharedPreferencesFirstTime;
//////
sharedPreferencesFirstTime = getPreferences
(Context.MODE_PRIVATE);
String firstTime = getResources().getString(R.string.saved_first_time);
firstTimekey = sharedPreferencesFirstTime.getString
(getString(R.string.saved_first_time),
firstTime);
crimeType = v.findViewById(R.id.crimeType);
Initializing a String Array
String[] plants = new String[]{
"Antisocial behaviour",
"Arson",
"Burglary"
};
Initializing an ArrayAdapter
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(
getActivity(), android.R.layout.simple_spinner_item, plants
);
Sets the layout resource to create the drop down views.
/*
Parameters : resource
the layout resource defining the drop down views
*/
spinnerArrayAdapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
Sets the Adapter used to provide the data which backs this
/*
setAdapter(SpinnerAdapter adapter)
Sets the Adapter used to provide the data which backs this Spinner.
*/
crimeType.setAdapter(spinnerArrayAdapter);
crimeType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//Get the text content
crime_string= parent.getItemAtPosition(position).toString();
//Get Position of the crime
selectionPosition=
parent.getItemAtPosition(position);
SharedPreferences.Editor editor = sharedPref.edit();
String key2 = crime_string;
editor.putString(getString(R.string.saved_login_key), key2);
editor.apply();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
//Another interface callback
}
});
Related
I have a spinner, which contains language options and its items are named from string resources depending on system language. I need something like an identifier for these languages attached to each item. For example, I need to know that the user selected "English" as an option (or "en" if we are talking about identifiers) even though when he selected it, he chose "Englisch" (if the user is german). So how can I attach these kinds of identifiers to my array-list items?
I'd suggest making a simple class to hold the required data.
public class Language {
private String identifier;
private String name; //localised name
...
//we want to show the localised data in the spinner
#Override
public String toString() {
return name;
}
Then just make a simple ArrayAdapter and overwrite the onItemSelected function of the spinner or just get the selected item whenever you wish to. Something like:
List listWithLanguages = getLanguages();
ArrayAdapter<Language> adapter = new ArrayAdapter<>(this, R.layout.spinner_item, listWithLanguages);
spinner.setAdapter(adapter)
...
String identifier = (Language) spinner.getSelectedItem().getIdentifier();
You can treat your string-array items as an identifier.
And can use get the selected item from setting up the listener
AdapterView.OnItemSelectedListener
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
Use a custom adapter that encapsulates the information you care about, then instead of building an adapter that creates a list of localized strings, you create an adapter that creates a list of objects that have the identifier and the localized string together.
Kotlin pseudo code:
val strings = loadLocalizedStringsFromArrayItems()
val identifiers = loadIndentifierStringsFromArrayItems()
val listOfPairs = identifiers.zip(string)
val adapter = ArrayAdapter<List<Pair<String, String>>>(listOfPairs)
val spinner.setAdapter(adapter)
// When clicking on the spinner item:
val pair = adapter.getItemAtPosition(clickedPosition)
val identifier = pair.first
val localizedString = pair.second
I already know how to save edittext contents to sharedpreferences but in spinners and radiogroups I still don't have a clue. Can you please give me snippets of codes how to do it? Thanks
For the data store is is not relevant which UI elements is used to display or modify the value. Here is a description how to store or retrieve various data types: http://developer.android.com/reference/android/content/SharedPreferences.html
So a spinner selection is simply an integer (or string if you like) and the choice for a radio group is simply whatever identifier (as string) you choose to represent that choice.
If the choices come from an array resource you may use the values from the array or the index into the array. Store/retrieve them in/from the shared preferences like you used to store and retrieve the text from the EditText.
This is the way that you can save the selected item of a spinner in sharedPreferences:
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
Object obj = parent.getItemAtPosition(pos);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
Editor prefsEditor = prefs.edit();
prefsEditor.putString("object", obj.toString());
prefsEditor.commit();
}
public void onNothingSelected(AdapterView<?> parent) { }
});
I have an array of Strings I'm populating a Spinner object with. However, I'd like to attach an ID to each element of the Spinner, so when the user selects an item, I have its ID to use to save to some other piece of data. How can I do this?
Create a class StringWithTag and use in place of the string name in the list like so :-
public class StringWithTag {
public String string;
public Object tag;
public StringWithTag(String stringPart, Object tagPart) {
string = stringPart;
tag = tagPart;
}
#Override
public String toString() {
return string;
}
}
in the add items to spinner part :-
List<StringWithTag> list = new ArrayList<StringWithTag>();
list.add(new StringWithTag("Oldman", "12345"));
list.add(new StringWithTag("Umpire", "987654"));
list.add(new StringWithTag("Squad", "ABCDEE"));
ArrayAdapter<StringWithTag> adap = new ArrayAdapter<StringWithTag> (this, android.R.layout.simple_spinner_item, list);
....
....
in the listener :-
public void onItemSelected(AdapterView<?> parant, View v, int pos, long id) {
StringWithTag s = (StringWithTag) parant.getItemAtPosition(pos);
Object tag = s.tag;
}
voila!
}
What do you mean by id. You can use ArrayAdapter to populate the Spinner. When item is selected just get the element from the adapter and save the data you want.
Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<MyObject> adapter = ... // initialize the adapter
adapter.setDropDownViewResource(android.R.layout.some_view);
spinner.setAdapter(adapter);
and when item is selected
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
MyObject selected = parent.getItemAtPosition(pos);
// save any data relevant with selected item
}
If you are storing your data in db you can use CursorAdapter and in onItemSelected to fetch the selected item id from the cursor.
I don't think you can attach an arbitrary ID to elements of a text array resource, if that's what you're using.
I think the simplest way to attach such an ID would be to either hard-code (if you're using a static text resource) or dynamically build (if you get the strings at runtime) a mapping from (String position in array)->(primary key).
EDIT: On the other hand, Mojo Risin has a point - you should check to see if the CursorAdapter API already does what you need for you.
Andrew Hi, it's been a long time but it's worth to write.
You can set a tag for each row when you'r inflating spinnerLayout in SpinnerAdapter:
spinnerView = inflater.inflate(spinnerLayout, parent, false);
spinnerView.setTag("Your Tag");
And then you can get the tag with:
yourSpinner.getSelectedView().getTag();
I think The best solution is to add one more spinner and fill it with the ids but make the visibility of it to gone
In the following code I am setting up a spinner, listening and detecting selections from the spinner.
The problem is I am trying to save the previously selected value so it is persistent between activity reloads, but when I reload the activity, the previously selected value is not set as the spinner value. The code is as follows :
final Spinner spinner = (Spinner)findViewById(R.id.Spinner_gender);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(this, spinnerID, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View itemSelected, int selectedItemPosition, long selected){
Editor editor = mGameSettings.edit();
editor.putLong(GAME_PREFERENCES_GENDER, selectedItemPosition);
editor.commit();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
);
//if( mGameSettings.contains(GAME_PREFERENCES_GENDER) ){
Toast.makeText(QuizSettingsActivity.this, "Detected(again): " + spinner.getSelectedItemPosition(), Toast.LENGTH_SHORT).show();
spinner.setSelection( spinner.getSelectedItemPosition() );
//}
I am using spinner.getSelectedItemPosition() to get the spinner selected index. Can anyone please tell me what I am doing wrong?
You are never reading from your SharedPreferences. You are writing to them (at least, I assume that is what mGameSettings is), but not reading from them.
spinner.setSelection( spinner.getSelectedItemPosition() );
This is a nonsense statement. You are setting the spinner's selection to its current selection. If you want to set the spinner's selection to the value from your SharedPreferences, you need to read the value from the SharedPreferences.
I found a solution to persisting the state of spinners in Android apps in simple situations.
In my app my spinner had three values (Normal, Important, and Urgent). Initially, these values were stored in a SQLite database as strings.
My solution involved storing the spinner values instead as integers in the SQLite database and then using the following code to set the spinner value when the activity was reloaded:
int temp = (int) memo.getInt(memo.getColumnIndexOrThrow(MemoDbAdapter.KEY_MODE));
mModeText.setSelection(temp);
This allowed me pass the data from the SQLite database directly without having to work out the position of desired selection from strings stored in the database. This worked for my simple Memo application but obviously won't work if you need to store the spinner output as strings in your database.
I declare my Spinner in the following manner (it's very static so I
have 2 string arrays in array.xml for titles and values)
<Spinner
android:id="#+id/searchCriteria"
android:entries="#array/searchBy"
android:entryValues="#array/searchByValues" />
I expect spinner.getSelectedItem() to return an array [title, value]
but in fact it returns just a title String. Is it ignoring
android:entryValues? How do I get a value, not a title from it? Is
this doable with XML only or do I need to create adapter and do it
programmatically?
Rather than the dual array method, why not fill your ArrayAdapter programmatically with objects of a known type and use that. I've written a tutorial of a similar nature (link at the bottom) that does this. The basic premise is to create an array of Java objects, tell the spinner about the, and then use those objects directly from the spinner class. In my example I have an object representing a "State" which is defined as follows:
package com.katr.spinnerdemo;
public class State {
// Okay, full acknowledgment that public members are not a good idea, however
// this is a Spinner demo not an exercise in java best practices.
public int id = 0;
public String name = "";
public String abbrev = "";
// A simple constructor for populating our member variables for this tutorial.
public State( int _id, String _name, String _abbrev )
{
id = _id;
name = _name;
abbrev = _abbrev;
}
// The toString method is extremely important to making this class work with a Spinner
// (or ListView) object because this is the method called when it is trying to represent
// this object within the control. If you do not have a toString() method, you WILL
// get an exception.
public String toString()
{
return( name + " (" + abbrev + ")" );
}
}
Then you can populate a spinner with an array of these classes as follows:
// Step 1: Locate our spinner control and save it to the class for convenience
// You could get it every time, I'm just being lazy... :-)
spinner = (Spinner)this.findViewById(R.id.Spinner01);
// Step 2: Create and fill an ArrayAdapter with a bunch of "State" objects
ArrayAdapter spinnerArrayAdapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, new State[] {
new State( 1, "Minnesota", "MN" ),
new State( 99, "Wisconsin", "WI" ),
new State( 53, "Utah", "UT" ),
new State( 153, "Texas", "TX" )
});
// Step 3: Tell the spinner about our adapter
spinner.setAdapter(spinnerArrayAdapter);
You can retrieve the selected item as follows:
State st = (State)spinner.getSelectedItem();
And now you have a bona fide Java class to work with. If you want to intercept when the spinner value changes, just implement the OnItemSelectedListener and add the appropriate methods to handle the events.
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
// Get the currently selected State object from the spinner
State st = (State)spinner.getSelectedItem();
// Now do something with it.
}
public void onNothingSelected(AdapterView<?> parent )
{
}
You can find the whole tutorial here:
http://www.katr.com/article_android_spinner01.php
So if you came here because you want to have both label and value in the Spinner - here's how I did it:
Just create your Spinner the usual way
Define 2 equal size arrays in your array.xml file. One for labels, one for values
Set your Spinner with android:entries="#array/labels"
In your code - when you need a value do something like this (no you don't have to chain it)
String selectedVal = getResources().getStringArray(R.array.values)[spinner
.getSelectedItemPosition()];
And remember - these 2 arrays have to match each other as far as number slots and positions
Abort, abort! I don't know what got into me but Spinner does not support android:entryValues attribute. That one is actually from ListPreference which does a similar thing (displays list of items in pop-up dialog). For what I need I will have to (alas) use the SpinnerAdapter