I have a problem with handling onSavedInstance
and onRestoreInstance
for my two spinners in app.
I have two SpinnerAdapter
that can be dynamically fill with pair of ArrayAdapter<String>
- adapter1/adapter2 and adapter3/adapter4.
In onCreate method app create 4 adapters for them, when user press button1
it fill spinnerFrom
and spinnerTo
with adapter1 and adapter2,when button2
fill spinners with adapter3 and adapter 4 respectively.
As i understant lifecycle - when screen rotates, android destroys app and then restore it from the beginning .
So in onSavedInstance
i put my spinner into bundle
savedInstanceState.putInt("from",spinnerFrom.getSelectedItemPosition);
savedInstanceState.putInt("to",spinnertTo.getSelectedItemPosition());
on restore i retrieve them from bundle:
spinnerFrom.setSelection(savedInstanceState.getInt("from"));
spinnertTo.setSelection(savedInstanceState.getInt("to"));
The problem is: when app restore it lose my adapters and they get null value.
To check it i created technical button and next code:
protected void checkAdapter () {
//get Adapter from spinners
SpinnerAdapter valueAdapter = spinnerFrom.getAdapter();
SpinnerAdapter resultAdapter = spinnertTo.getAdapter();
if (valueAdapter == null | resultAdapter== null) {
Toast.makeText(this, “adapter null” , Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(this, “adapters not null” , Toast.LENGTH_SHORT).show();
}
}
Question: How properly put AdroidSpinner and it's adapter into OnSavedInstance bundle and then restore it onRestoreInstance in case when it populates not in onCreate but in onClick methods? Thanks in advance!
App java code:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
protected double getEnteredValue;
protected SpinnerAdapter checkAdapter;
protected int pos;
protected ArrayAdapter<String> adapter 1, adapter2, adapter3,
adapter4;
//butterknife bindings
@BindView(R.id.unit_From_spinner)Spinner spinnerFrom;
@BindView(R.id.unit_To_spinner)Spinner spinnertTo;
@BindView(R.id.radio_result_group) RadioGroup resultGroup;
@BindView(R.id.radio_value_gropu) RadioGroup valueGroup;
@BindView(R.id.valueEditTextView) EditText valueEdit;
@BindView(R.id.resultView) TextView resultView;
@BindView(R.id.conver_button) Button convertButton;
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString("result",resultView.getText().toString()); savedInstanceState.putString("value",valueEdit.getText().toString()); savedInstanceState.putInt("from",spinnerFrom.getSelectedItemPosition);
savedInstanceState.putInt("to",spinnertTo.getSelectedItemPosition());
savedInstanceState.putInt("radGroup1",resultGroup.getCheckedRadioButtonId());
savedInstanceState.putInt("radGroup2", valueGroup.getCheckedRadioButtonId());
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.unifiedlayout);
ButterKnife.bind(this);
//adapters for spinners
adapter1 = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item,getResources().getStringArray( R.array.adapter_1) );
adapter2 = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item,getResources().getStringArray(R.array. adapter_2));
adapter3 = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item,getResources().getStringArray( R.array. adapter_3) );
adapter4 = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item,getResources().getStringArray(R.array. adapter_4));}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
resultView.setText(savedInstanceState.getString("result"));
valueEdit.setText(savedInstanceState.getString("value"));
spinnerFrom.setSelection(savedInstanceState.getInt("from"));
spinnertTo.setSelection(savedInstanceState.getInt("to"));
super.onSaveInstanceState(savedInstanceState);
}
//OnClick
@OnClick({R.id.button1, R.id.button2,R.id.button3,R.id.button4} )
public void setViewOnClickEvent(View view){
switch(view.getId()){
case R.id. button1:
fillSpinner(adapter1, adapter2); // fill spinner with values
break;
case R.id. button2:
fillSpinner(adapter3,
adapter4);
break;
//button for check if any adapter active
case R.id.buttonAdapter:
checkAdapter () ;
break;
}
}
//fill spinners when user checks radiobutton in radiogroups
protected void fillSpinner (final ArrayAdapter<String> spinnerToAdapter,
final ArrayAdapter<String> spinnerFromAdapter){
valueGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup valueGroup, int checkedId) {
pos = valueGroup.indexOfChild(findViewById(checkedId));
switch (pos) {
case 0:
spinnerFrom.setAdapter(spinnerToAdapter);
break;
case 1:
spinnerFrom.setAdapter(spinnerFromAdapter);
break;
}
}
});
resultGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup resultGroup, int checkedId) {
pos = resultGroup.indexOfChild(findViewById(checkedId));
switch (pos) {
case 0:
spinnertTo.setAdapter(spinnerToAdapter);
break;
case 1:
spinnertTo.setAdapter(spinnerFromAdapter);
break;
}
}
});
}
//simple method for check if both spinners has null value
protected void checkAdapter () {
//get Adapter from spinners
SpinnerAdapter valueAdapter = spinnerFrom.getAdapter();
SpinnerAdapter resultAdapter = spinnertTo.getAdapter();
if (valueAdapter == null | resultAdapter== null) {
Toast.makeText(this, “adapter null” , Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(this, “adapters not null” , Toast.LENGTH_SHORT).show();
}
}
EDIT: Answer isn't perfect it don't works how i want yet, but this way give me possibility to save adapter: 1.Create method to retrieve string array from adapter that want' to be saved :
public static String[] getStringArray(SpinnerAdapter adapter) {
String[] a = new String[adapter.getCount()];
for (int i = 0; i < a.length; i++)
a[i] = adapter.getItem(i).toString();
return a;
}
2.In onSavedInstanceState put next code:
// here i saving arraylist that ussualy i get from resources.
savedInstanceState.putStringArray(ADAPTER_TO,getStringArray(spinnerFrom.getAdapter()));
savedInstanceState.putStringArray(ADAPTER_FROM,getStringArray(spinnerFrom.getAdapter()));
3.In restoreInstance create new adapter that will fill yours spinner with values and use savedInstanceState.getStringArray(ADAPTER_TO) to populate with saved values :
toAdapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item, savedInstanceState.getStringArray(ADAPTER_TO));
fromAdapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_item, savedInstanceState.getStringArray(ADAPTER_FROM));
//use spinner.setAdapter to set created adapter.
spinnerFrom.setAdapter (fromAdapter)
spinnerTo.setAdapter (toAdapter)
This still not work properly as i want, but if you want to save spinner state on rotation screen you can try use this logic.
You can achieve this using two methods. 1) (recommended) Using ViewModels (architecture components) 2) using save and restore state.
1). You can create a viewModel and whenever the user selects something, call the ViewModel with the specified value. By observing the ViewModel, you can get the latest changes to that value (even after rotation changes) because ViewModel will stay alive.
3) Hold user's selection in a local variable inside your activity, then in save and restore, put
and get
your value like following:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("firstSpinnerPosition", variableThatHasTheChangedPosition);
savedInstanceState.putInt("secondSpinnerPosition", variableThatHasTheChangedPositionForSecond);
// other stuff.
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
variableThatHasTheChangedPosition = savedInstanceState.getInt("firstSpinnerPosition");
variableThatHasTheChangedPositionForSecond = savedInstanceState.getInt("secondSpinnerPosition");
//notify your adapter of the changes
}