I have two Spinners. In onCreate i setup listeners for them. At some other places i populate them.
Now I am not sure what the best practice is for handling these spinners when screen orientation changes. Should i store all values and selected item in sharedPreferences somehow or in savedInstanceState?
If you can, please advise me in a prefered way and also include some sample code for handling spinners. The goal here is to keep the values and selected item thru the lifecycle.
I will include code at request or if needed.
Thanks
Try this, onSaveInstanceState for Screen Orientation for saving your selected value of spinner,According to my choice shared preference is not good choice for saving selected values of spinner.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("mySpinner", mySpinner.getSelectedItemPosition());
// do this for each or your Spinner
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize all your visual fields
if (savedInstanceState != null) {
mySpinner.setSelection(savedInstanceState.getInt("mySpinner", 0));
// do this for each of your text views
}
}
Add android:configChanges="orientation|screenSize" in your AndroidManifest file, it will keep spinner value selected on orientation change.
User Spinner Like this:
mSpinner = findViewById(R.id.spinner);
ArrayList<String> stringArrayList = new ArrayList<>();
for (int i = 0; i < 6; i++) {
stringArrayList.add("List Item " + i);
}
ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, stringArrayList);
spinner.setAdapter(arrayAdapter);
Related
I'm new to Android (this is my first application) and I made a GridView in an Activity which I'd like it to be responsive according to screen position (portrait / landscape). Of course I made some custom layout values of GridView rows width for portrait as well as for landscape, and it works perfectly.
Except that, on every screen orientation change, the GridView is reloading again. And that's not good for user experience. I only like the GridView (and definitely its rows) to adjust to new screen width without doing all the onCreate() instructions (retrieving GridView's data from internet, assigning retrieved data in a HashMap object, setting the GridView's Adapter, then display the GridView's rows).
I went through many forum threads and some Google documentation that talk about restoring simple values, but never found an answer for restoring a GridView without having it to reload again.
I read about onSaveInstanceState() and onRestoreInstanceState(), but I didn't know how to use them in my case (GridView case).
Could any one provide a simple code sample for this? Or at least some headlines to follow?
Here's some of what I tried in my code, in the Activity class :
private Parcelable mListInstanceState;
private Parcelable mAdapterInstanceState;
private GridView gridView = null;
private MyAdapter myAdapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = (GridView) findViewById(R.id.gridview);
// Check whether we're recreating a previously destroyed instance
if(savedInstanceState != null) {
// Restore value of members from saved state
mListInstanceState = savedInstanceState.getParcelable("gridview");
mAdapterInstanceState = savedInstanceState.getParcelable("adapter");
}
else {
// Retrieve data from internet, fill HashMap object,
// set Adapter and display GridView only for the first time the activity is created
attemptToDisplayGirdViewItems();
}
}
#Override
protected void onSaveInstanceState(Bundle state) {
// Save activity state
super.onSaveInstanceState(state);
state.putParcelable("gridview", gridView.onSaveInstanceState());
// state.putParcelable("adapter", myAdapter);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Retrieve and restore activity state
// Restore state members from saved instance
mListInstanceState = savedInstanceState.getParcelable("gridview");
mAdapterInstanceState = savedInstanceState.getParcelable("adapter");
super.onRestoreInstanceState(savedInstanceState);
}
You don't need to save the views. If they have ID, they'll be saved automatically (such as scroll position of a GridView). What you need to save is the adapter's data set.
Your adapter presumably holds a list of items. Unless these items are primitives or String or implement Serializable, they need to implement Parcelable for this to work.
See here how to do that: How can I make my custom objects Parcelable?
Your adapter needs a getItems method which returns the data set - an ArrayList of your parcelable items. It also needs to have a setItems(...) method or a constructor taking a list of items as parameter.
Then your activity will look like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = (GridView) findViewById(R.id.gridview);
myAdapter = new MyAdapter(); // Create empty adapter.
if(savedInstanceState != null) {
ArrayList<MyItem> items = savedInstanceState.getParcelableArrayList("myAdapter");
myAdapter.setItems(items); // Load saved data if any.
}
gridView.setAdapter(myAdapter);
}
#Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
state.putParcelableArrayList("myAdapter", myAdapter.getItems());
}
I have application with listview(one line contains textview, imageview, ratingbar) and my own adapter. When I rotate the screen after sorting listview (I choose this option in menu), it backs to form before sorting.
I tried override onSaveInstanceState:
#Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelable("listView", listView.onSaveInstanceState());
}
and fragment onCreate:
listView.setAdapter(adapter);
if(savedInstanceState!=null)
{
mListInstanceState=savedInstanceState.getParcelable("listView");
listView.onRestoreInstanceState(mListInstanceState);
}
But it doesn't work. Should I override onRestoreInstanceState too or use something else?
The problem is when orientation change your Activity is recreated and when onCreate() is called you are setting the adapter with the default list items.
If you don’t maintain different layout for landscape/portrait, you can simply avoid the Activity recreate by just adding configChanges in manifest for your Activity
android:configChanges="orientation|screenSize" // add this line
This will avoid recreating the Activity and same layout will be used to fit on screen width. Make sure your listView layout width is set to match_parent.
If you still want your Activity to recreate, then you need to remember the last selected filter when onSaveInstanceState is called on orientation change
#Override
public void onSaveInstanceState(Bundle outState)= {
outState.putString(“selectedFilter","some name");
super.onSaveInstanceState(outState);
}
And then when onCreate in called after rotate, you can get the selectedFilter name
String filterName = null;
if(savedInstanceState != null){
filterName = savedInstanceState.getString("lastFilter");
}
Finally , set the listView with items based on the filter name.
if(filterName != null && filterName.equalsIgnoreCase("some name")){
// filtered list items
} else {
// default list items
}
Here is my scenario:
I have a MainActivity and a CustomListViewActivity. In my MainActivity, I have 1 button and 1 spinner. On click of the button, I pass the selected spinner value to the CustomListViewActivity via Bundle and using Intents.
Now, in my CustomListViewActivity, I have a ListView that uses ArrayAdapter for populating it. I send a ArrayList from MainActivity, say for example
items = [abc]
In my CustomListViewActivity, I receive the same and use it to populate my ListView. The first time I do this, my value gets populated. The second time I do the same, the value existing is now replaced with the new one and the ListView shows one item instead of showing two.
So basically the problem is that the ListView is not updating and not showing both the items. Instead it shows me a single item always.
Here are snippets of my code
MainActivity.java
//code inside button click
..
{
items.add(spinner1.getSelectedItem().toString());
Bundle bundle =new Bundle();
bundle.putStringArrayList("data",items);
Intent i = new Intent(MainActivity.this,MyListViewActivity.class);
i.putExtras(bundle);
startActivity(i);
finish();
}
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
Log.i("App","onSave");
icicle.putStringArrayList("data",items);
}
#Override
protected void onRestoreInstanceState(Bundle icicle2) {
// TODO Auto-generated method stub
super.onRestoreInstanceState(icicle2);
Log.i("App","onRestore");
icicle2.putStringArrayList("data",items);
}
MyListViewActivity.java
private ArrayList<String> myItems;
private static String[] titles;
CustomListViewAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_main);
listView = (ListView) findViewById(R.id.list1);
rowItems = new ArrayList<RowItem>();
adapter = new CustomListViewAdapter(this,R.layout.list_item, rowItems);
listView.setAdapter(adapter);
b=getIntent().getExtras();
if(b!=null)
{
myItems=b.getStringArrayList("data");
titles= new String[myItems.size()];
titles = myItems.toArray(myItems);
}
...
int i=0;
while(i<titles.length) {
item = new RowItem(titles[i]);
//rowItems.add(item);
Log.i("ROW", ""+rowItems.size());
i++;
adapter.add(item);
listView.setAdapter(adapter);
}
adapter.setNotifyOnChange(true);
adapter.notifyDataSetChanged();
}
}
How to make the ListView maintain the current data as well reflect the added data?
Thanks in advance
EDIT : Forgot to mention one more thing. In my MyListViewActivity class I have a button above the ListView that on clicked takes me to my MainActivity so that I can add a new Item again. So when I go back to MainActivity and try and add a new Item , it's the new Item that get displayed rather than showing both the previous and the new one
You need to persist and restore your items list in MainActivity's onSaveInstanceState and onRestoreInstanceState methods.
You also probably don't need to close the MainActivity by calling finish() every time you start the ListView activity but that depends on your application.
Basically, the problem you are having is that items is being recreated with each new instance of MainActivity. Since you finish MainActivity, a new instance is used every time you access that activity (and I assume you thought that items would just keep getting items added to it).
I have an Android app with a listview that updates the listview when the user presses a button. The app has two actionbar tabs. When I switch between the tabs, rotate the screen, or press back to exit out of the activity, all the data in the listview disappears. I need the data to remain. I know that at least with the orientation change I can save the data in onSaveInstanceState(). So I save a String[] in savedInstanceState, and retrieve the String[] in onCreateView(). This seems to work fine, it reads the data properly. Then I attempt to update the listview. This also seems to read the data and work properly, only the listview does not update and instead remains blank. My code for this is:
if (savedInstanceState != null) {
lvArray = savedInstanceState.getStringArray("lvArray");
setupListView();
} else {
lvArray= new String[LISTVIEW_LIMIT];
for (int i = 0; i < LISTVIEW_LIMIT; i++) {
lvArray[i] = " ";
}
setupListView();
}
private void setupListView() {
if (listview.getAdapter() == null) {
ArrayAdapter<String> listviewAdapter = new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_list_item_1, lvArray);
listview.setAdapter(listviewAdapter);
}
registerForContextMenu(listview);
}
So as I said, I go through this, it reads the data properly, it sets up an ArrayAdapter of the data, and sets the adapter for the the listview. It all seems to work, only it doesn't actually update it. I know all the data's there but it's still not working?
Also, I have the ability to set the listview to different sizes (by LISTVIEW_LIMIT). This works fine, except it also removes all the data already in the listview. How can I keep the data instead of recreating the array when the limit changes?
And what would be the best way to save this in onPause() or onStop(), so that I could keep the listview up even if back is pressed or the tab is switched?
EDIT: Changed to use notifyDataSetChanged(), still not working:
lvStopwatch = (ListView) view.findViewById(R.id.list_stopwatch);
stopwatchTimes = new String[TOTAL_TIMES];
for (int i = 0; i < TOTAL_TIMES; i++) {
stopwatchTimes[i] = " ";
}
setupListView();
if (savedInstanceState != null) {
stopwatchRunning = savedInstanceState.getBoolean("stopwatchRunning", false);
stopwatchTimes = savedInstanceState.getStringArray("stopwatchTimes");
stopwatchAdapter.notifyDataSetChanged();
} else {
stopwatchRunning = prefs.getBoolean("stopwatchRunning", false);
Log.d("savedPASS", String.valueOf(stopwatchRunning));
}
private void setupListView() {
if (lvStopwatch.getAdapter() == null) {
stopwatchAdapter = new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_list_item_1, stopwatchTimes);
lvStopwatch.setAdapter(stopwatchAdapter);
}
registerForContextMenu(lvStopwatch);
}
try this
adapter.notifyDataSetChanged();
Keep listview data save in some data structure.
I find HashMaps best for this.
Call Sales adapter again when you want to populate.
adapter=new MyAdapter(dataHashMap);
listView.setAdapter(adapter);
Found the solution. For some reason it doesn't display the values properly when restoring them in the onCreateView() method. I restored them in the onCreate() method of the fragment instead . I didn't really change much other than moving the saveInstanceState check into the onCreate() method, but now it works.
Hi I am trying to save some values in my activity but I'm having a problem when I save it with onSaveInstanceState and restore with onRestoreInstanceState, I am saving an int years and it saves the first time the screen changes orientation, the spinner repopulates and sets it at the last value , but not when I switch back the orientation again.
My orientation is set to landscape in my manifest, and I have the two save and restore method overridden but it doesn't seem to work, do I need to do something in onPause aswell?
here is my code:
int years;//global variable
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Spinner spinnerYears = (Spinner) findViewById(R.id.spinYears);//Spinner
final ArrayAdapter <Integer> adapter = new ArrayAdapter <Integer>(this,android.R.layout.simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for(int i=0;i<=100;i++)
{
adapter.add(i);
}
spinnerYears.setAdapter(adapter);
years = spinnerYears.getSelectedItemPosition();
}//onCreate
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("MyInt", years);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Spinner spinnerYears = (Spinner) findViewById(R.id.spinYears);//Spinner
final ArrayAdapter <Integer> adapter = new ArrayAdapter <Integer> (this, android.R.layout.simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for(int i=0;i<=100;i++)
{
adapter.add(i);
}
spinnerYears.setAdapter(adapter);
TextView tvYears = (TextView) findViewById(R.id.tvYears);//spinner Tv
tvYears.setVisibility(TextView.GONE);
int myInt = savedInstanceState.getInt("MyInt");
spinnerYears.setSelection(myInt);//
Toast.makeText(getBaseContext(), "Restored int"+myInt, Toast.LENGTH_LONG).show();
}
Because you don't handle the event of changing orientation, so everytime you change orientation, your program (or Activity) is re-created, which means the onCreate() method is called always; which leads to a result that onSaveInstanceState() and onRestoreInstanceState() never being called.
It's being explained here in Android Documentation: http://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges
In order to fix this, in AndroidManifest.xml , adding this attribute:
android:configChanges="orientation"
to avoid Activity restarted and, well, good luck with that!
In onRestoreInstanceState(), you never assign the value back the the variable years. You assign it to an int and then disregard it. So when onSaveInstanceState() is called, years hasn't been set yet and it saves that unset value (0).
If you change your getInt() line towards the bottom to be:
years = savedInstanceState.getInt("MyInt");
spinnerYears.setSelection(years);
it should start working. Good Luck!