I have a Spinner with a bunch of state names. In onCreate(), I set it to a default value. The index 0 in the Spinner array is "Alabama"
String state = "California"; //preset to this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_state_and_drivers_license);
statesSpinner = (Spinner)findViewById(R.id.states_spinner);
adapter = (ArrayAdapter<String>)statesSpinner.getAdapter();
statesSpinner.setSelection(adapter.getPosition(state));
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, RESULT_CAMERA);
}
However, after onResult, the Spinner is once again set to "Alabama". Meaning it reverts back to index 0 of the array, even though I thought it should keep its existing selected value.
Edit: I put setSelection(position) into onCreate, onResume, and onDestroy. Still, when I return from the camera intent, the spinner still resets and does not go to my selection.
Its possible that calling the Camera Activity is not saving your state, in essence, calling onDestroy. I am not to sure. This other question, which also deals with camera intent had a similar issue. I would add a log in onDestroy, and check if its being called when calling the camera Activity. This other question also makes a bit of sense because normally your state should remain the same when calling a new Activity.
After some quick research it seems because of orientation change and possible memory issues, your state cannot be saved. You can also just do what the other answer says because since its preset, making sure its always that on onResume will be a easy workaround.
Its really simple, same issue I resolved by follow this post really help me.
many stuffs lose there (like picked image,spinner etc..) state, you can recover simply by following link.
How do I preserve the state of a selected spinner/dropdown item on orientation change?
Thanks,
static int position=-1;
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int arg2, long arg3) {
position=arg2;
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
#Override
protected void onResume() {
super.onResume();
if(position!=-1){
spinner.setSelection(position);
}
static int POSITION =0;
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
POSITION=pos;
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
#Override
public void onResume() {
super.onResume();
spinner.setSelection(POSITION);
}
Related
The following code returns a null value. Can anyone please tell me why? I'm looking to use the returned value to send it to another activity in an intent the Choice string is declared in the class this code belongs to:
public String SetupBreakfastSpinner()
{
Choice = "";
SpinnerSelector= ArrayAdapter.createFromResource(HomeActivity.this, R.array.breakfastArray, android.R.layout.simple_spinner_item);
SpinnerSelector.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Breakfast.setAdapter(SpinnerSelector);
Breakfast.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Choice= parent.getItemAtPosition(position).toString();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return Choice;
}
In method SetupBreakfastSpinner you are initializing Choice to empty string. When you call this method you are setting adapter to spinner correctly but immediately returning Choice which is still empty.
As you have to send Choice value to another activity, you have two options:
Approach 1: When user choose an Item in spinner, onItemSelected callback gets called:
void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Choice= parent.getItemAtPosition(position).toString();
//start your activity here, pass Choice value in the Intent
}
Approach 2: Assuming that you have some button, which when clicked you start activity, in onClick of button you can start activity
void onClick(View v){
//Start activity, pass Choice in Intent
}
Keep in mind that values that changes on certain event, for example
here Choice variable gets updated when user choose values, you need
to be careful before using such variables, such variable might be
null.
I have an Activity with a Spinner. This Activity will load information from the internet based on the Spinner selection and show it in this Activity. When the first time the Activity is launched, the Spinner will be selected by default. I use Spinner#setOnItemSelectedListener so that each time the Spinner is selected, a method which will load information from the internet will be triggered.
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
String option = (String) parent.getItemAtPosition(pos);
loadInfoFromInternet(option);
}
When the orientation of the phone is changed, the Activity will be destroyed and recreated. I've stored the Spinner information and also the information I got from the internet in the savedInstanceState's bundle. With it, I managed to save the state of the Spinner and the info from internet.
The problem is with the info I got from the internet. When the orientation changes, Spinner will be recreated and select an option. This will trigger OnItemSelectedListener which will call onItemSelected. The loadInfoFromInternet will be triggered again. It makes my data which I stored in savedInstanceState be replaced.
What I want is when the orientation changes, I want the Spinner not to trigger loadInfoFromInternet so that I can show the information from previous state instead of loading from internet again.
Initially, I come up with the following idea:
private boolean isNewState = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
if (savedInstanceState == null) {
isNewState = true;
}
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
String option = (String) parent.getItemAtPosition(pos);
if (isNewState) {
loadInfoFromInternet(option);
}
}
With the above solution, when the orientation changes, the information is not loaded from the internet again. That's what I want, but, when I select another option, the loadInfoFromInternet will not be triggered since it's not a new state (isNewState = false). This is not what I want.
What you described in your question sounds on track. Inside your onCreate() method you can check the Bundle parameter which gets passed in. If the bundle is not null, then you can assume that you have saved state for your spinner and you can load that state.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
if (savedInstanceState == null) {
isNewState = true;
}
else {
int sIndex = savedInstanceState.getInt("S_INDEX");
Spinner spinner = (Spinner) findViewById(R.id.yourSpinner);
spinner.setSelection(S_INDEX);
}
}
and add logic to onSaveInstanceState() to save the index state of the spinner:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
Spinner spinner = (Spinner) findViewById(R.id.yourSpinner);
int sIndex = spinner.getSelectedItemPosition();
savedInstanceState.putInt("S_INDEX", sIndex);
}
Note that onSaveInstanceState() will get called each time your phone changes orientation. All you need to do is store the state of the activity in the Bundle to persist it across changes.
This question already has answers here:
saving spinner state using sharedpreferences in android
(1 answer)
Shared Preference & Spinner Not Maintaining State
(4 answers)
Closed 8 months ago.
I'm doing an Android app which can get data from a web service & load it into spinner. I need to maintain the selected data state of the spinner while I go to some screen & come back. For example, if I'm getting data from the web service as 1.apple 2.orange 3.grapes & loading it into the spinner, then I select orange. When I go to some other screen & come back, the selected spinner data should be orange. But it again loads data from the server into the spinner. Can anybody help me to resolve this?
My code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
if (Constants.SPINNER != null ) {
spinner.setSelection( Constants.SPINNER);
} else {
//WebCall here for getting data
}
//...
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent,
View view, int arg2, long arg3) {
Constants.SPINNER = spinner.getSelectedItemPosition();
In Constant class:
public static Integer SPINNER="";
You can follow the below procedure:
You need to save state of your spinner so this would be helpful to you.
1.) Apply this after creating spinner object
sectionNameSpinner.setSelection(getPersistedItem());
2.) Create these methods according to you to save the state of your spinner selected item
private int getPersistedItem() {
String keyName = makePersistedItemKeyName();
return PreferenceManager.getDefaultSharedPreferences(this).getInt(keyName, 0);
}
protected void setPersistedItem(int position) {
String keyName = makePersistedItemKeyName();
PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(keyName, position).commit();
}
private String makePersistedItemKeyName() {
return currentUserName + "_your_key";
}
3.) Set its state as the spinner selection changed:
sectionNameSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View view, int position, long itemId) {
setPersistedItem(position);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
When you "go to some other screen" you should do so via a new activity. Then, after you finish that new activity, the spinner selection activity will resume and the selection state will be as it was prior to starting the second activity.
Make sure you are not hitting the webservice in OnResume() of your activity.
Make sure you are not finishing the current activity by calling finish() before proceeding to the next activity.
And check whether data available or not before web hit (here you can avoid unnecessary web hits)
It appears that android's Spinner class (and possibly ListView in general, although I don't know for sure) calls your OnItemSelectedListener's onItemSelected() method after you call setAdapter(), even if the user hasn't explicitly selected anything yet.
I can see how this would be useful in many situations, but there are times when I only want onItemSelected() to be called when an item is actually specifically selected.
Is there a way to control this behaviour and have Spinner NOT call onItemSelected() after setting the adapter?
I haven't used this solution for very long yet so I'm not totally confident that it works as expected, but I've had luck so far with this workaround:
spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
protected Adapter initializedAdapter = null;
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Always ignore the initial selection performed after setAdapter
if( initializedAdapter !=parent.getAdapter() ) {
initializedAdapter = parent.getAdapter();
return;
}
...
}
}
Is there a better way?
Add listener to spinner like below:
spinner.post(new Runnable(){
public void run()
{
spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
...
}
}
}
});
I've used the setTag and getTag methods, and created a resource id called "spinnerstate".
Then whenever I programmatically set the adapter, I set the "spinnerstate" tag to "init", and in the fired event, set it to "ready" and ignore the event. (note my code is Mono for Android se it will look different):
Set Adapter:
profileSpn.SetTag (Resource.Id.spinnerstate, "init");
profileSpn.Adapter = new ArrayAdapter (this, Android.Resource.Layout.SimpleSpinnerItem, items.ToArray ());
Item Selected event:
string state = (string)((Spinner)sender).GetTag (Resource.Id.spinnerstate);
if (state == "init") {
((Spinner)sender).SetTag (Resource.Id.spinnerstate, "ready");
return;
}
I agree that this is not desired behaviour in almost 100% of cases, and I don't think it's good design on the part of Google, but there you go.
I did similar things before, I used count value. Using parent adapter object is incomplete because it can be a problem when view is refreshed or getView() called again.
Therefore, I recommend that using array of counter.
At first, define array of count in adapter globally.
private int isInitializedView[];
And then initialize it on getView().
isInitializedView[position] = 0;
In the selection listener, do something that you want if it already initialized.
holder.mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
isInitializedView[position]++;
if(isInitializedView[position] > 1) {
// do someting that you want
}
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {}
});
(Note that isInitializedView[position]++; can be come after if() routine, and only trigger event when this value is >0 . It's your choice.)
I had three spinner in my activity and all spinner adapter data has been filled at runtime(from web-service data after call from onCreate method). So it automatically call onItemSelected(AdapterView<?> parent, View view, int position, long id) method of spinner.
I solved this issue by using onUserInteraction() method of activity
check this method that user is interacting with spinner or not. if yes then perform the action else not
Declare isUserIntract boolean variable globally
in onItemSelected method use following procedure
If(isUserIntract)
{
//perform Action
}
else{
//not perform action
}
use below code in activity
#Override
public void onUserInteraction() {
super.onUserInteraction();
isUserIntract = true;
}
I'm creating a spinner and I've added an OnItemSelectedListener to it.
However I've noticed that it fires on create.
Now I was wondering if there was a way to ignore/discard it.
I know I could use a boolean value, but that's a bit "dirty".
Here is my solution.
I need to ignore the first item selection event because there is a dependency between the Route Grade Spinner and the Route Checkbox.
And all my controls are setup based on a previous visit to the activity.
// Used to count the number of times the onItemSelected gets fired
private int mGradeSelectionCount = 0;
private void attachHandlers() {
OnItemSelectedListener gradeRangeSelectionMadeListener;
gradeRangeSelectionMadeListener = new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
// If the counter is 0 then we can assume that it is android firing the event
if (mGradeSelectionCount++ < 1) {
return;
}
if (mCmbGradeFrom.getSelectedItemPosition() == 0) {
// Uncheck the Route checkbox
mChkTypeRoute.setChecked(false);
} else {
// Check the Route checkbox
mChkTypeRoute.setChecked(true);
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// Dont care, keep the same values as before
}
};
mCmbGradeFrom.setOnItemSelectedListener(gradeRangeSelectionMadeListener);
mChkTypeRoute.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) {
mCmbGradeFrom.setSelection(0);
mCmbGradeTo.setSelection(0);
}
}
});
}
This may help you.
#Override
public void onItemSelected( AdapterView<?> parent, View view, int position, long id)
{
if(view!=null && view.getId()!=0){
//do your code here to avoid callback twice
}
}
You should not attempt to prevent the call to the OnItemSelectedListener.
By default, Android Spinners select the first item returned by the Adapter, and therefore the OnItemSelectedListener is called to trigger some action on that item.
I would advise that the first item in your Spinner Adapter be a blank item, and your OnItemSelectedListener can ignore that blank item based on its id.
If anyone else comes across this question, it may be worth having a look at a related question I asked a while ago, which has several answers with good ideas on how to work around this issue.
Well I think I found nice solution for me, I had it in mind from start but...
I have custom wrapper class based on android Handler , that is called DoLater, and also there is custom Adapter based on Listener so you cant copy paste this but you will get idea. Dangerous thing is just that somehow delay 500 can be to long and View can be already destroyed (when user do some wired stuff quickly or phone gets slow...) so DoLater cares of that so it is not called when activity is not resumed. But this way OnItemSelectedListener is not fired on create.
public void onResume() {
super.onResume();
new DoLater(this, 500) {
public void run() {
new OnSpinnerSelectedAdapter(getBowSpinner()) {
protected void onItemSelected(int position) {
onBowSelected(position);
}
};
}
};
}