Android ListView not retaining values through orientation change - android

I am a bit perplexed on what Android holds onto in a view orientation change and what it doesn't.
Some things it seems it holds onto nicely, other things it seems it doesn't.. So I am not sure if it is my code, or something else. (I assume I am doing something stupid)
What I have is a view with a listview in it, the listview has a simple adapater and an array of map items to put into the listview.
When the orientation changes, I know that the activity is destroyed and recreated, so I assume that my simple adapater and its tie to the listview are gone.. so the listview won't rotate populated and I'll need to use the onRetainNonConfigurationInstance or onSaveInstanceState methods to pass through either the adapter or the list of values?
This seems excessive, I can't believe the sharp guys at Google don't have an easier way to handle this.. The listview has an ID, and after orientation I can add items to it and it works fine, but it just doesn't hold onto the values it had before.
Is my only way around this to pass the list content through explicitely? Is it the fact I am creating a new SimpleAdapter and linking it to the list in the onCreate that is causing the issue? Or is it the fact the array of Items I have linked to the adapter is whiped out when the activity is?? This seems like something that shouldn't require this much work to accomplish.. am I missing something?

No, you could also have a persistent model through Activity lifecycle like this :
define a singleton app, with a method to get your singleton model.
At on create get your datas from your model.
As your model will no be recreated but will persist, this can be used as a workaround for preserving objets through rotation change.
Regards,
Stéphane

Related

how to saveInstanceState of a view defined in getView() method

I have MainActivity with a ViewPager that hosts three tabs and their respective classes extend Fragment. One of the tabs has a layout with a ListView, the
layout of the each item in the listView is as follows
TextView, checkBox and imageview
This ListView has customized adapter class that extends BaseAdapter.
What I want to do is, to save the check state of the Checkboxes of the ListView.
in the class that extends Fragment I override the method onSaveInstanceState, the problem is the checkBoxes are defined in the getview() method in the
class that extends BaseAdapter! I want to know how can I save the check state of the checkboxes in the method "onSaveInstanceState"?
I think you might be misunderstanding the purpose of BaseAdapter. BaseAdapter-derived classes are meant to serve as an interface between a dataset and the AdapterView in which you display that dataset's information (and/or interact with it.)
With that in mind, I kind of think the easiest way to accomplish what you're doing is going to be to keep track of whether or not the item is checked using a boolean as part of the dataset. For example, if your dataset is an ArrayList<SomeObjectYouMadeUp>, you'll want to add a boolean member to SomeObjectYouMadeUp; set it during the CheckBox's OnCheckedChangeListener, and use it to determine whether the CheckBox should be visually checked during getView().
That might take some rethinking of your code, but trust me, you're probably going to want to do it. It's possible to do it the way you are describing, but it won't be easy or reliable; you'll want to get individual access to each visible view in your AdapterView using the method described here, but again I have to recommend against this.
The biggest reason is that onSaveInstanceState occurs most commonly during configuration changes - for example, a screen rotation. This means it is almost certainly an incorrect assumption that you'll be displaying the same Views. Say there are 10 Views visible in portrait orientation, and 5 visible in landscape. So the user rotates to landscape - which 5 do we get? Do you know for sure? You'll have to check each new View against some identifying information you probably also had to keep in onSaveInstanceState - and what if one of the new Views wasn't visible before the rotation?
The list of questions goes on. Do yourself a favor: save the check state with the rest of your dataset, and let Android figure it out for you.

Is it okay to change a ListView's adapter dynamically?

Instead of creating multiple activities, I would like to change the ArrayAdapter of the ListView as needed. I don't see any mention in the API about whether or not it is okay to call setAdapter() more than once.
To be more specific, say I would like to start an activity that has a ListView. In this example, the ListView is initialized with a listView.setAdapter(this) from, say, a CategoryArrayAdapter.
Then a user selects a category. Without starting a new activity, the code will set a new adapter for the same ListView. The new adapter, say ItemArrayAdapter calls listView.setAdapter(this).
Does someone have experience having done this successfully or know of a specific reason why this shouldn't be done?
I don't see any mention in the API about whether or not it is okay to call setAdapter() more than once.
The simple answer is YES, and I have done similar sort of things before.
This is exactly the reason why Adapter is existed and provided in the API. The actual content (Model) and how it is rendered (View) for each list items is isolated and implemented inside android.widget.Adapter, instead of directly bound to android.widget.AdapterView. As long as your adapter is properly implemented, you can swap/change the actual underlying adapter that bound to the ListView, simply by calling the setAdapter() method.
Resetting the adapter is ok, but notice, that there might be a GUI glitch when doing so, as the view whose adapter is being changed has to be redrawn with the new data. Aside from this you should be fine.

Show / Hide Listview SectionIndex on demand

i implemented a listview which implements SectionIndexer ...
everything fine so far.
Normally the items are sorted by Name, but i also offer the option to sort the list in a different way - by distance (from the user to the objects).
So, when the list is sorted the 2nd way, i want to hide the previously generated SectionIndex.
I'm just not able to do so.
I tried, re-writting most of the methods,
I tried it with a separation in the Constructor (clear why it doesnt work, it doesnt get called a second time)
I even tried it with implementing a second listadapter, and just using a different one? Even in this case the SEctionIndex is shown! I really don't understand this one.
So would be really great, if anyone knows whats going on :)
thanks a lot, mike
Your observations are correct. Let me tell you first why the constructor never gets called the second time. SectionIndexer are a special kind. They create the index only once for a particular set of data and re-use them on that adapter. The bigger issue which I had come across was when the underlying data changed for the adapter, the sectionIndexer still remained the same.
Check my Question and the answer there.
Coming back to your query here.
If you change the orientation after selecting the second option, you would observe that the constructor will get called and you will be able to re-populate the sectionIndex again. So basically you need to call onSizeChanged again and get the sectionIndex repopulated.
When you Short your List with different way ,you have a two option to load again .
after filled those new collection for adapter
1) you can make a notify this adapter .
2) you can fill set adapter again .
If by SectionIndexer which remains displayed you mean the section overlay you can achieve this by calling setFastScrollEnabled(false) before to switch to your other listadapter which does not implements SectionIndexer.

Is there a way to call BaseAdapter.notifyDataSetChanged() on a single object?

Is there a way to call BaseAdapter.notifyDataSetChanged() on a single element in the adapter.
What I am trying to do is update the data and reflect those changes in the containing ListView. The problem is that sometimes the change is so small that it seems ridiculous that I have to refresh the whole view rather than the single item in the view that has been updated.
I am not aware of such method. If it's really important, you can always find individual item view to update. But I don't think that it worth it as Android is pretty efficient in updating list views. So it will not do much extra work (definitelly not going beyond items currently visible on the screen).

Refresh view display when underlying data changes

I have seen this question answered a few times in which it is suggested to use the method notifyDataSetChanged() from BaseAdapter.
Is there a way to refresh when your application does not use any adapters? I have a simple application where I use a few activities with preferences, and relative layouts with text views and buttons. At the moment I do not use any of the adapters like SimpleAdapter or ArrayAdapter or CursorAdapter. It seems like in my case I have to create one of them just to get to use notifyDataSetChanged()? There is no easier way for me?
Looks like (I may be mistaken, but it really looks like) you don't catch the purpose of those classes - SimpleAdapter, ArrayAdapter or CursorAdapter. They are expected to work with ListView inside of an Activity (or even better - inside of a ListActivity). If you don't use ListView then those adapers are most likely useless for you.
I assume you have your data persisted in some way (SharedPreferences or file). So if you start any of your Activities, then it just reads the data to populate the views. In this case nothing extra is needed. In case if you need to reload data for a currently visible Activity, then just reread the data from persistent storage and repopulate the views.
If your data is changing and you need to refresh your view, how is the data actually changing? Is it in a separate thread or, do you just want something to happen periodically (polling an RSS feed, or something)?
I had a similar problem. I had a radio group, and each radio button had a label. When the screen rotated, I used a different layout with a radio group & radio buttons with the same IDs. I was calling setContentView() in onCreate(): and after rotation, the “old” labels would show up on the new layout (bizarre). When I moved setContentView() to onResume, everything seems to update ok. Thanks to Arhimed for his answer above.

Categories

Resources