each time my activty receives a message (from some TCP listening thread), it does
mLstAdpChatScreen.add(line);
updateUI();
private void updateUI()
{
runOnUiThread(new Runnable()
{
public void run()
{
mLstAdpChatScreen.notifyDataSetChanged();
mLstAdpChatScreen.notifyDataSetInvalidated();
mLstVwChatScreen.requestLayout();
mLstVwChatScreen.invalidate();
}
});
}
While this approach works on most of my listviews and they do get updated, it does not for a certain listview. I must be missing something :-?
Thank you
That should work for most of the cases however I got the same problem when trying to update listview from database. I called adapter.notifyDataSetChanged(); too, but listview didn't update at all although I could confirmed the data was changed, and the ArrayList's size increased.
In the end, I implemented a method inside my custom Adapter extending from BaseAdapter just to call notifyDataSetChanged there, like
public class MyAdapter extends BaseAdapter{
public void updateData(){
this.notifyDataSetChanged();
}
}
Then in Activity, I just call adapter.updateData(). And this worked for me. Very weird.
Related
For an app i'm creating I have a RecyclerView that gets filled with data from a Firebase Database. This RecyclerView is also in a fragment that's used in a Viewpager. All and all I am able to make it work, but what I notice is, is that on the first run it takes a while for the fragment to show it's content in the RecyclerView, so I wanted to add a ProgressBar to it as an Asynchronous Task.
My Task:
private class ProgressTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
mProgressLinearLayout.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
loadColleagueData();
mListener = initRealTime();
mAdapter = new CustomAdapter(mUserList, getActivity());
return null;
}
#Override
protected void onPostExecute(Void res) {
mRecyclerView.setAdapter(mAdapter);
mProgressLinearLayout.setVisibility(View.GONE);
}
}
Now this works actually. The ProgressBar gets shown and also is hidden again once it's done. But the problem is, is that it's done in such a short time that it's not visible. So I only know that it works because of debugging. What still takes a while is the RecyclerView actually showing the content.
So what I guess my problem is, is that not so much getting the data from the Database is the thing that takes a while, just more setting the Adapter to the RecyclerView and showing it's content is the thing that takes a while.
Now from what I understood is, is that it's not possible to set the adapter in the doInBackground since you can't do anything with the views outside of the main ui thread. So I was wondering if there is a way to hide the ProgressBar only once the content is visible in my RecyclerView?
(If this is a duplicate question i'm awfully sorry, my search on the internet did not manage to help me)
You should use the FirebaseDatabase callbacks, you don't need to use an AsyncTask for this. If you what to listen for single event, that means that you just want to download the data, then use this:
mProgressLinearLayout.setVisibility(View.VISIBLE);
DatabaseReference node = FirebaseDatabase.getInstance().getReference().child("your_node");
node.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
loadColleagueData();
mListener = initRealTime();
mAdapter = new CustomAdapter(mUserList, getActivity());
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mProgressLinearLayout.setVisibility(View.GONE);
If you want your Adapter to be allways up-to-date you can attach listeners to that specific nodes using addChildEventListener() or addValueEventListener() (docs here). Or you can use this grate library, you just need to copy one file:
https://github.com/mmazzarolo/firebase-recyclerview
I have a custom array adapter than extends ArrayAdapter, but the notifyDataSetChanged() method just plain doesn't show up(and does not work if you try it).
class matchAdapter extends ArrayAdapter<Match> {
public matchAdapter(Context context, List<Match> matches) {
super(context, R.layout.match_layout, matches);
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
The above is from my adapter class. Would notifyAll() do the same thing?
Your listAdapter is declared as having the type ListAdapter, which doesn't have the method you expect (notifyDataSetChanged). You need to make it at least BaseAdapter or cast it to a BaseAdapter(I am assuming your MatchAdapter is at least a BaseAdapter - if not, well, calling such a method would make no sense:-) )
((BaseAdapter)listAdapter).notifyDataSetChanged();
I'll write an example, it's not a real code but it's how you have to do this.
Create your List
ArrayList<matchList> matchList = new ArrayList<matchList>();
Create an Adapter
adapter = new matchAdapter(this, matchList);
Set the Adapter
YourListView.setAdapter(adapter);
You change the stuff on your List
matchList.add(Stuff for your list);
Notify now that List has changed doing :
adapter.notifyDataSetChanged();
Hope it helps to you, if it does not, just type a comment and I'll try to update my answer.
Edit
I'll give you some examples...
When you want to call notifyDataSetChanged() just do this :
List.clear();
List.addAll(YourStuff);
adapter.notifyDataSetChanged();
Other method could be, you are using an AsyncTask so your onBackGround() you could make it returns items for your list, then on your onPostExecute update the adapter.
Example :
#Override
protected List<matchList> doInBackground(String... params) {
List<matchList> items = loadUpdatedDataset(params);
return items;
}
#Override
protected void onPostExecute(List<matchList> itemschangeds) {
updateAdapterDataset(itemschangeds);
adapter.notifyDataSetChanged();
}
Have you tried compiling and running the app? If there are any syntax errors above your matchAdapter (like a missing ; or "), it'll screw the autocompletion up.
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.
I am working on tabHost with 4 tabwidget, my all four tab widget has a listActivity that shows list of items from different arraylist objects set from Json parsing Bean classes..
Now the application is working f9 but,,, about 5 in 1 time ratio it shows exception that my adapter is reset but listView unable to display data as the adapter is set from background thread.
I can't provide the adapter data from same UI thread b'coz my Bean classes and Data manager are defined else where....
I have used adapter.notifyDataSetChanged() where required...
Please do not suggest that...
With Regards,
Arpit
Even if things are defined some place else you should still be able to set the adapter using:
runOnUiThread(new Runnable() {
#Override
public void run() {
list.setAdapter(adapter);
}
});
or simply post a runnable to the UI thread:
view.post(new Runnable() {
#Override
public void run() {
list.setAdapter(adapter);
}
});
Hope this helps, Christoffer
I'd recommend using a Handler (http://developer.android.com/reference/android/os/Handler.html) to perform all changes to the adapter: create a Handler instance for each Activity and then send a Message (http://developer.android.com/reference/android/os/Message.html) to that handler from your data manager/bean classes with the new data for the list adapter. You can then update the adapter safely from the Handler as it will perform its work on the UI thread.
Short writeup is here: http://www.tutorialforandroid.com/2009/01/using-handler-in-android.html and there are a number of other questions on SO that describe it.
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.