In my adapter I have a method to set information:
public void setData(List<ListItem> dataList) {
this.listItems = dataList;
notifyDataSetChanged();
}
But after I call this method, the data is refreshed and my View move up. I don't want this behavior, because if someone is changing something in the end of the page, the focus is lost.
There is any way to set data from an adapter and don't lose the focus?
You must call adapter.notifyDataSetChanged() from the UI thread. May be this & this SO posts can help you.
Related
I have been working with RecyclerView for a while. I am following lazy loading, so I am showing 10 data on the view each time. If user scroll to the bottom, the page re-load from the TOP! however, I want to stay where it was previously! So, I have tried to use
recyclerView.scrollToPosition(position);
However, this breaks the UI flow!
My second try is using onSaveInstanceState() and onRestoreInstanceState(Bundle state); However, that does not work! My page is re-loads to the top!
Parcelable state = layoutManager.onSaveInstanceState();
layoutManager.onRestoreInstanceState(state);
I have tried every other methods, apparently none is working for me!
Any help would be highly appreciated! Thanks in advance!
Note : Make sure that you are not initialising or calling setAdapter() method each time after updating your dataset. If not, then
You have to update your data list and call notifyDataSetChanged() which will update your adapter from existing position.
Let's say you have stored your data into ArrayList mData;
Your getItemCount() would be
#Override
public int getItemCount() {
if (mData != null && mData.length() > 0)
return mData.size();
return 0;
}
Now create one more method in your adapter which you will called each time whenever you will get new data from server. This method will simply override your dataset and will update your adapter
private void updateDataSet(ArrayList<String> mData){
this.mData = mData;
notifyDataSetChanged();
}
I have done this functionality before 2 days ago
I share my idea with you
Make
Listview lv; //Assume Find view by Id
List<Model> models = new ArrayList();
Now Make an Adapter and assign blank models
CustomAdapter adapter = new CustomeAdapter(context,models);
lv.setAdapter(adapter);
Now when you have new data to load with lazylodaing
do this
models.addAll(newModels); //new ModelList
adapter.notifyDataSetChanged();
Thats it.
This is the default behaviour Recycler View to recycle/resuse views. As in official docs:
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
If you are having any view related issues then save your view state in your List<Object> like setting visible item or not per position. And in your onBindViewHolder method as per position show/hide your view.
I have two listview, like listview_1 and listview_2. I wanna refresh the listview_2 while listview_1 is refreshed.
My code like this:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
But it don't work, listview_1 can refresh but the listview_2 can't.
And at that moment what I found is that listview_1 was on focus.
And then I tried to set focus to other views before ran the method, both of them didn't refresh. It likes to refresh a listview only if the listview has focus.
What's more I found that when I called the method to refresh, listview_2 didn't, and then I set focus to listview_2, refreshed itself!
So, What all I want to ask is:
How to refresh two listview at one moment in Android?
What's more code:
//init two listview there
public void init() {
listview_1 = (ListView)findViewById(R.id.listView1);
listview_2 = (ListView)findViewById(R.id.listView2);
adapter1 = new MyListViewAdapter(mContext);
adapter2 = new MyListViewAdapter(mContext); //I have tried use different adapter, that also didn't work.
listview_1.setAdapter(adapter1);
listView_2.setAdapter(adapter2);
}
the real code of upside snippet is:
public void updateTwoListView(int currentPosition) {
adapter1.updateCurPos(currentPosition);
adapter2.updateCurPos(currentPosition);
}
and in MyListViewAdapter.java:
public void updateCurPos(int currentPosition) {
mCurrentPos = currentPosition;
notifyDataSetChanged();
}
And I will call method like listViewManager.updateTwoListView(1) outside to refresh.
Any reply is appreciated.
You have called listview_1 twice. Just change one of them to listview_2 as below:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
It seems the problem of your code is that you call getAdapter().
Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
Source: http://developer.android.com/reference/android/widget/ListView.html#setAdapter(android.widget.ListAdapter)
The solution is save your Adapter as member variable in your activity and call the notifyDataSetChanged()from there.
See more on this question's answer: https://stackoverflow.com/a/31893525/2742759
Hi friends i have a listview and the contents are fetched from a webservice call. In that webservice call, there are fields like
"OGType": "ORG" and "OGType": "GROUP"
If click a button, the listview must shows the item having "OGType": "ORG", and hide the item having "OGType": "GROUP". Hope you understand what i meant. Please anyone help me for that. Thanks in Advance.
Try to set new data (only with ORG) to adapter and then call
adapter.notifyDataSetChanged();
You can do it in your getView Method in your Adapter Class. That's the header
public View getView(int pos, View convertView, ViewGroup, parent)
There you can properly hide the element(s) you want, you know, using the method setVisibility()
For more help you can take a look here
You can create a custom adapter and pass data to it in the form of Array or ArrayList (ArrayList is better when dealing with Custom Adapters). Whenever you need to add or remove the data from ListView, just add or remove the item to or from you ArrayList and call notifyDataSetChanged() on your custom adapter and it will update the ListView automatically.
In your case, whenever you click a button, edit you ArrayList and call your custom adapter's method called notifyDataSetChanged() and that's it. You'll see every time you call this method ListView will refresh itself if you have made any changes to the data. Hope it helps.
NOTE - CUSTOM ADAPTER IS NOT COMPULSORY. ANY ADAPTER CAN BE USED e.g SimpleAdapter, ArrayAdapter etc.
You can use a visible list and filters lists. You should use "visible" for complete the BaseAdpter as always, then, you can change the pointer of visible to other list (all, filter...)
Don't worry by the memory, are pointers, you only have each element only once.
public class MyAdapter extends BaseAdapter {
private ArrayList<MyItem> visible;
private ArrayList<MyItem> all;
private ArrayList<MyItem> filter;
public MyAdapter(ArrayList<MyItem> items) {
all = items;
visible = all; //Set all as visible
filter = new ArrayList<Item>();
for (Item i : items)
if (i.getType().equals("ORG"))
filter.add(i);
}
//Complete adapter using "visible"
public void showOnlyOrg() {
visible = filter;
notifydatasetchanged();
}
}
The non hackish way will be to remove the items from your Collection which you use to generate the listview and then call notifyDataSetChanged();
I've been fooling around with Android but I'm stuck. I have a adapter class that
sets an image in an imageview for each item in my gridView. I use the observer pattern to notify the activity that calls the update method and it refreshes the adapter with notifydatasetchanged and that invalidates the gridview itself and the imageView.
The problem is that when i change an object (which has a reference to a drawable), and try to update, nothing happens in the imageview. I've tried to debug and the objects are changed so i don't understand why it doesn't update...
Also, with this it works perfect to make the images disappear, so that's pretty akward..: shape.setImage(android.R.color.transparent)
#Override
public void update(Observable arg0, Object arg1)
{
// Toast.makeText(this, "I am notified",0).show();
adapter.notifyDataSetChanged();
gridView.findViewById(R.id.picture).invalidate();
gridView.invalidate();
}
This is an example of an object that needs to be showed:
public class Square extends Shape
{
public Square()
{
setImage(R.drawable.square);
}
public String print()
{
return "s ";
}
public String getName()
{
return "Square";
}
}
my adapter:
public class GridAdapter extends ArrayAdapter<Shape>
{
Context context;
int layoutResourceId;
List<Shape> data = null;
public GridAdapter(Context context, int layoutResourceId, List<Shape> data)
{
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
public View getView(int position, View convertView,ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_item, parent, false);
rowView.setBackgroundResource(R.drawable.customshape);
ImageView imgView =(ImageView)rowView.findViewById(R.id.picture);
imgView.setImageResource(data.get(position).getImage());
return rowView;
}
I think the actual problem here is updating the drawable from outside the UI thread. notifyDataSetChanged() isn't the answer. The dataset didn't change, in my case at least. The dataset changed and I set the drawable to null (which worked). Later, when the image finished loading, I wasn't updating from the UI thread, so the GridView didn't know it was supposed to learn about the invalidation of the ImageView.
The answer in my case was to use AsyncTask which automatically uses the UI thread and thread syncs.
Note that notifyDatasetChanged() is for when the getViewId() changes in the adapter — which isn't the same as and actually has nothing to do with when the drawable changes. Also note that setImageDrawable() automatically invalidates the ImageView. There's actually no need to call ImageView.invalidate() or any other invalidate(). You just have to update the drawable in the UI thread, and AsyncTask comes with all the right baggage to not only do it at the right time, but in such a way that the GridView can learn about it before it updates the various canvases and drawable caches.
I learned most of the above from the Google Android dev pages and from source diving for hours on end. Curiously, source diving in Android Studio (ctrl-B) is actually easier than slogging through all the docs hoping to stumble on the right paragraph that explains the problem. Though, the problem is explained nicely here:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
I cannot comment, so I am going to share my thoughts here, let me know in the comments if I'm missing something.
Seems like you need to add the following method in your GridAdapter:
public void setData(List<Shape> stuff) {
data.clear();
data.addAll(stuff);
notifyDataSetChanged();
}
Now, wherever in your activity you created the adapter, you should have a List that was passed to create the GridAdapter. Let's call that initial list 'data1'.
Assuming by 'refresh' you mean that you want to modify an existing item. You need to find that item in data1 and make the changes. Then you need to find the GridAdapter instance that you have already created and then use the setData method and pass data1.
Hope this is not totally useless info for you.
Note: it would be helpful if you posted more of your code.
The problem is that when i change an object (which has a reference to
a drawable), and try to update, nothing happens in the imageview.
Lets have a look at the doc:
public void notifyDataSetChanged()
Notifies the attached observers that the underlying data has been
changed and any View reflecting the data set should refresh itself.
the only reason that when you call notifyDataSetChanged() and it dose not update your gridview is that your adapter data set and your object are two different things. that means your gridview data has not changed. you must change those objects that you passed to your gridView constructor (List data). if you change any of them and then you call notifyDataSetChanged() it will work. The references of your object and the adapter data must be the same.
another things that I have seen on the net is you must change the data set of adapter by manipulating it with functions like (add(), insert(), remove(), clear(), etc.).
Problem solved lol, i just made a new adapter instead and it worked
I'm having a strange issue with a custom implementation of Android's ArrayAdapter. To give some background, I'm trying update a ListView's contents while preserving the current scroll position.
I have a service which executes a thread to update data that's displayed in the ListView. That data is stored in an ArrayList and that ArrayList is used to generate some custom ArrayAdapters for the ListView. The adapters are also updated when an item in the ListView is pressed (either adding or removing an item). I used to just create new adapters each time there was any type of change and then set this new adapter to the ListView. This worked, but caused the ListView to scroll to the top each time. Given the nature of my application this was undesirable. The current scrolled position in the ListView must be maintained between updates.
Instead of creating new adapters I began clearing the adapter that I needed to update using the adapter's clear() method, then rebuild the adapter's items by using the adapter's add() method. Both of these methods are being called on the adapter. The adapters are all set to notifyDataOnChange in their constructors so I don't have to manually call notiftyDatasetChanged() each time (although given my issue I've tried calling it manually as well to no avail).
Here's what my custom adapter looks like:
public class RealmAdapter extends ArrayAdapter<Realm>
{
Context c;
public RealmAdapter(Context context, int resource, int textViewResourceId)
{
super(context, resource, textViewResourceId);
setNotifyOnChange(true);
c = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
...
}
...
}
Long story short, here's my issue. When I call clear() on the adapter, the adapter is not being cleared.
Here's a snippet from my onPostExecute in my thread that does updating. I'm being sure to put it here so it's updating on the UI thread. I also have this exact code copied in a private method in my UI activity. This code does not work in either place:
appState.favoriteAdapter.clear();
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
for(Realm r : appState.favorites) {
appState.favoriteAdapter.add(r);
}
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
As an example, if the above adapter had 3 items in it, calling a getCount() right after the clear() is returning 3 instead of 0. Likewise, if the appState.favorites ArrayList only has 2 items in it, the getCount() after the loop is still returning 3, not 2. Because the adapter is not responding to any of these calls it makes it impossible to update in any fashion. I can post a Logcat later if that will be helpful, but there are no exceptions or anything useful being displayed.
After busting my head for hours, the issue I appear to be having is that the adapter is not responding to calls to any methods that alter it. I've tried passing an empty ArrayList into the adapter's super() call, this does not help. Am I missing something or using the ArrayAdapter incorrectly? I've searched all over and I've already checked a lot of the common problems such as modifying the underlying array and expecting it to update, not calling (or in my casing setting to the adapter) notifyDatasetChanged(), and using an unsupported operation on the underlying collection.
The declaration of the favoriteAdapter is very simple and is contained in my Application class:
public RealmAdapter favoriteAdapter;
Here is the initialization of the favoriteAdapter from above:
if(appState.favoriteAdapter == null) {
appState.favoriteAdapter = new RealmAdapter(c, R.layout.list_item, R.layout.realm_entry, appState.favorites);
}
else {
appState.favoriteAdapter.clear();
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
for(Realm r : appState.favorites) {
appState.favoriteAdapter.add(r);
}
Log.d(LOG_TAG, "COUNT: " + appState.favoriteAdapter.getCount());
}
The above code is in both my UI thread and the thread that downloads the refreshed data.
Underneath the code above a filter is put in place:
if(appState.favoriteAdapter != null && RealmSelector.realmFilter != null) appState.favoriteAdapter.getFilter().filter(RealmSelector.realmFilter.getText().toString());
Would the filter affect clearing the list? Logic would dictate not...
I had filters being applied to the custom ArrayAdapter. Apparently this interferes with adding and removing items from the adapter itself? I added this code to my method and it is now working:
if(appState.favoriteAdapter != null && realmFilter != null) {
appState.favoriteAdapter.getFilter().filter(realmFilter.getText().toString());
}
I'd love if anyone could explain why this matters. I thought filters were meant to select subsets of items in the adapter. In my testing I was leaving the text box that is used for the filter empty, thus no actual filter text should have been applied. Again, if someone knows what's going on and could explain to me why this fixes the problem I'd love to know.