My implementation of ArrayAdapter is such that it listens for changes in the under lying data. So any changes in the data, the adapter is notified and it calls the notifydataSetChanged()
public class MyAdapter extends ArrayAdapter implements ObjectStateListener {
#Override
public void onObjectStateChanged() {
/*Call appropriate functions as the underlying data as changed.
A good way of doing that would be to retrieve only the positions of the filtered values
so that the original dataholder can be used but display only certain indices
*/
Log.v(TAG, "FilterCriteria changed. Trigger fired");
this.filterPositions = Helper().getFilteredPositions(filterCriteria, mAppartments);
Log.v(TAG, "CALLING NOTIFYDATASETCHANGED()...");
notifyDataSetChanged();
Log.v(TAG, "FINISHED CALLING NOTIFY DATASET CHANGED");
}
}
In the above code the function onObjectStateChanged() is called whenever there is change in the data and in turn it calls notifyDataSetChanged(). To test if the onObjectStateChanged() is called correctly, I have put a bunch of Log statements as you can see. All those logs appear in logcat. But getView() is not getting called after calling notifyDataSetChanged() and hence the listview is not getting refreshed.
Why is this happening? notifyDataSetChanged() is supposed to ensure that getView() gets called and the new data is reflected in the ListView right?
Definition of ObjectStateChangeListener
public interface ObjectStateListener {
public void onObjectStateChanged();
public void listenForStateChange(Object o);
}
If you are deleting or inserting a new value on the list then whenever there is change in adapter list notifystatechange() will be called so just after inserting or deleting the value call notifystatechange () it will refresh the listview.
I've had to stop using notifyDataSetChanged() on my AutoCompleTextViews as they're not refreshing either. I just keep a local copy of the adapter and then reset it with the new dataset when it's changed.
Be sure your ArrayAdapter is set to notify on change (it is by default), and you technically shouldn't even need to make that call to notifyDataSetChanged() based on the docs: http://developer.android.com/reference/android/widget/ArrayAdapter.html
First update the data where you have kept it's reference in the adapter and then call the notifyDataSetChanged(). You will have to pass in the new data as well.
Related
I have a simple implementation of RecyclerView with an adapter inside the onResponse method of network call. How can I remove all previous RecyclerView items or refresh RecyclerView?
I have used adapter.notifyDataSetChanged(); and recyclerView.invalidate(); but none of them worked.
I will suggest you use a different approach
use asynchronous method
use variable which array of object, save data you get from network call in that variable
each you call a new request, clear the variable, add data from network call in that variable and refresh the recyclerView
Create a new instance of your adapter and then call recyclerview.setAdapter(newAdapter);
This will remove your old adapter and set the new adapter with the updated items.
If you just want to update the items in the current adapter then create a method inside your adapter to do so:
public void addItems(ArrayList<EventObject> eventList) {
this.eventList.addAll(eventList);
notifyDataSetChanged();
}
And then call adapter.addItems(moreItems);
You need to clear your list before calling notifyDataSetChanged().
Use the following line of code
adapter.clearData();
Don't forget to add this method
public void clearData() {
int size = this.myList.size();
this.myList.clear();
this.notifyItemRangeRemoved(0, size);
}
}
Create your adapter once, outside your OnResponse method. Inside your adapter, have a method for setting the items like:
public void setItems(ArrayList<MyObject> items){
this.items = items;
notifyDataSetChanged();
}
Then in your onResponse method you can call adapter.setItems(items);
Following Steps will help you
After successfully receive response, clear your data set using .clear() method.
Add Newly received data to the model.
Notify the adapter.
Suggestion-
Don't instantiate your adapter, each time after receiving the data.
Use a public method inside your adapter to do this operation also adding the data.
I want to populate a listView with data retrieved from DB asynchronously,
the problem Is that if I set the adapter, it throws null pointer because the data not arrieved yet, when I recieve data one method is executed, so what I can call in this method to populate my listview? I tried passing the layout to this class to populate directly the listview when the data is recieved but don't worked (nothing happened)
I thought using AsyncTask was a good idea adding wait() and when this "retriever data method" is triggered call notify() but I don't know how to call notify() from an asynctask from another class...
I'm also not sure if asynktask is the best way of doing this, any ideas?
I'm using retrofit2 if it helps
Code of listview create/populate
private List<TmOfsDTO> prepareList() {
List<TmOfsDTO> list;
try {
// Create list of items
ListObtainer listObtainer = new ListObtainer(this);
list = listObtainer.getTmOfsDTOList(user); // this method returns list of objects from DB
} catch (Exception e) {
list = null;
e.printStackTrace();
}
return list;
}
private void populateListView(List<TmOfsDTO> lista) {
// Build Adapter
OrderAdapter orderAdapter = new OrderAdapter(this, 0, lista);
// orderAdapter.getView()
Log.d("LSO", ".....");
// Configure listview
//View rootView = View.inflate(this, R.layout.activity_ordenes, null);
ListView listView = (ListView) findViewById(R.id.lvOrdenes);
listView.setAdapter(orderAdapter);
//listView.invalidateViews();
//listView.refreshDrawableState();
Log.d("LSO", ".......");
Last update:
**
I was doing right the notify when I was recieving data, passing the adapter to the class and calling:
orderAdapter.notifyDataSetChanged();
but the problem is I was missing to add each item with:
orderAdapter.add(orden);
before notify, now seem to work good**
As you logcat show above the lista is null. You are passing this list to the adapter. But if you have not initialized the variable lista it will throw a null pointer exception.
Suggest to initialize the List you passing to the adapter. Then when the data comes in you add the data lista and call the method adapter.notifyDataSetChanged()
Following seems to cause the null pointer exception
} catch (Exception e) {
list = null;
e.printStackTrace();
}
So beside initializing you should also not assign null.
You'd be best using a RecyclerView, anyway. This is part of the new support libraries and is way more efficient than the older ListView.
Some key questions here are whether or not the database is local. If your have an sqlite3 database on the phone that you're loading from then you should have written some classes that load the database information into objects that you can store into an array and pass into the RecyclerView.Adapter very easily.
If you are loading this remotely, then you would be 100% better off syncing the data onto your phone using an AsyncTask before trying to load the RecyclerView, otherwise you'll get those errors.
You could load ONE item into an ArrayList from a remote database, pass that to the RecyclerView, and then carry on loading from the remote database and notifying the RecyclerView of a change upon each item being added to the list.
Create a different constructor for your adapter, one that does not receive data to display in it. When you have that, it will not crash.
To get your data inside, create a local List of your items and populate it with something like:
public void setData(List<MyObject> data){
this.mData = data;
notifyDataSetChanged();
}
Also, don't forget to handle possible null pointer errors in methods such as getItem.
lets say we are in viewDidLoad method. I'd suggest you to do the following:
in your adapter class create public method: setData, which calls adapter.notifyDataSetChanged()
send request to backend by passing callback function
display loading/progress dialog
initialize adapter by passing empty array(not null)
when callback is fired and you get the list call adapter's setData and hide the progress dialog.
If you are using Fragments just call setAdapter() another time after data extraction
Ok, so ive spend two days on this and I have tried everything under the sun and Google :L
Basically, if I add or delete something from my server, I want to update my listview which is in mylistfragment from my detailfragment to reflect the changes on the server. The changes have occur ed through clicking either a delete or add button in my detail fragment.
I have a callback method which has everything that I need to repopulate the listview with I just cant seem to get the listview to update.
Any help would be much appreciated.
My callback code is as follows :
public final Handler myCallBackAll = new Handler() {
#Override
public void handleMessage(Message msg) {
ListView lv = (ListView) view.findViewById(R.id.listView1);
if (msg.obj == "No Response") {
TextView tv2 = (TextView) view.findViewById(R.id.textView2);
tv2.setText("No Response. Please check your internet connection");
tv2.setVisibility(View.VISIBLE);
lv.setVisibility(View.INVISIBLE);
} else {
Beer beers = new Beer();
ArrayAdapter<Beer> arrayAdapter = new ArrayAdapter<Beer>(
getActivity(), android.R.layout.simple_list_item_1,(List)msg.obj);
lv.setAdapter(arrayAdapterNew);
arrayAdapter.notifyDataSetChanged();
}
}
};
It doesnt throw any errors just doesnt work
How my callback is called is here
if (isBound) {
myBinder.getAllBeer(myCallBackAll);
}
Its a bounded service I have to use, a stipulation of the project. All this code works, just mylistview wont update
You say that you have already have the callback set up, so I am assuming the callback is being fired accordingly. If that is the case, make sure you update the data source (Array, List, etc) you are using in your adapter to reflect the changes you made in detailfragment.
Also, don't forget that every time you add, edit, delete data from your adapter's data source, you must call mAdapter.notifyDataSetChanged() to tell the adapter something in your data changed.
EDIT
Try creating your handler this way instead: public final Handler myCallBackAll = new Handler(Looper.getMainLooper())
notifyDataSetChanged() must be executed on the main UI thread. When you create a new handler it will execute on its own thread, so you need to make sure it does execute on the UI thread. Take a look at here for more information
finally figured it out, may not be the best approach but it does work, i had declare my listview as a static variable in my main activity, i then reference this variable in both fragments and it works a treat :P
I will be very grateful if someone can help me one this :)
I have a Custom Adapter (extending ArrayAdapter), and on the objects it displays (movieDatas), there is a property that vary with time (downloadProgress)
Since I use this adapter in multiple places, I wondered wether it is possible for my CustomAdapter to listen to every movieDatas.downloadProgress property, and then update itself ? Thus, not using ArrayAdapter.notifyDataSetChanged from the activity, but the adapter would take the decision to update by itself.
Previously, I used a Timer on every Activity that called myListView.invalidate() every 5 seconds, but I wondered if the adapter could handle the changes by itself ?
Thank you very much for your help, I begin in android development.
I don't know how you're doing it, but it sounds like you could totally use a callback to implement it.
1) Create an interface like this:
public interface OnDownloadProgressChangeListener{
public void onProgress(int progress);
}
2) Add this to your MovieData object:
// We use an ArrayList because you could need to listen to more than one event. If you are totally sure you won't need more than one listener, just change this with one listener
private ArrayList<OnDownloadProgressChangeListener> listeners = new ArrayList<OnDownloadProgressChangeListener>();
public void addDownloadProgressChangeListener(OnDownloadProgressChangeListener listener){
listeners.add(listener);
}
public void clearDownloadProgerssChangeListeners(){
listeners.clear();
}
//Add any handlers you need for your listener array.
// ALWAYS use this method to change progress value.
public void modifyProgress(int howMuch){
progress+=howMuch;
for (OnDownloadProgressChangeListener listener : listeners)
listener.onProgress(progress);
}
3) Override your custom adapter add method
#Override
public void add(final MovieData item){
item.addDownloadProgressChangeListener(new OnDownloadProgressChangeListener(){
public void onProgress(final int progress){
// Add your logic here
if (progress == 100){
item.update();
}
}
});
super.add(item);
}
4) Whenever an item gets modified, call notifyDataSetChanged() on your adapter. You can even add it after the super.add(item) line in the add implementation, but this is extremely inefficient if you're going to add a lot of items: Add them first then notify the changes.
This tutorial uses a SimpleAdapter which works fine, but I need to update the arrays in the adapter when new data is entered.
Could you please guide me on how to update a ListView using something other than a SimpleAdapter?
Use a ArrayAdapter backed by an ArrayList. To change the data, just update the data in the list and call adapter.notifyDataSetChanged().
If you create your own adapter, there is one notable abstract function:
public void registerDataSetObserver(DataSetObserver observer) {
...
}
You can use the given observers to notify the system to update:
private ArrayList<DataSetObserver> observers = new ArrayList<DataSetObserver>();
public void registerDataSetObserver(DataSetObserver observer) {
observers.add(observer);
}
public void notifyDataSetChanged(){
for (DataSetObserver observer: observers) {
observer.onChanged();
}
}
Though aren't you glad there are things like the SimpleAdapter and ArrayAdapter and you don't have to do all that?
SimpleListAdapter's are primarily used for static data! If you want to handle dynamic data, you're better off working with an ArrayAdapter, ListAdapter or with a CursorAdapter if your data is coming in from the database.
Here's a useful tutorial in understanding binding data in a ListAdapter
As referenced in this SO question
Most people recommend using notifyDataSetChanged(), but I found this link pretty useful. In fact using clear and add you can accomplish the same goal using less memory footprint, and more responsibe app.
For example:
notesListAdapter.clear();
notes = new ArrayList<Note>();
notesListAdapter.add(todayNote);
if (birthdayNote != null) notesListAdapter.add(birthdayNote);
/* no need to refresh, let the adaptor do its job */
I created a method just for that. I use it any time I need to manually update a ListView. Hopefully this gives you an idea of how to implement your own
public static void UpdateListView(List<SomeObject> SomeObjects, ListView ListVw)
{
if(ListVw != null)
{
final YourAdapter adapter = (YourAdapter) ListVw.getAdapter();
//You'll have to create this method in your adapter class. It's a simple setter.
adapter.SetList(SomeObjects);
adapter.notifyDataSetChanged();
}
}
I'm using an adapter that inherites from BaseAdapter. Should work for any other type of adapter.