I have an exception I never thought I would see. A class cast exception of the adapter when removing a footer view from a ListView (sic).
java.lang.ClassCastException: com.test.MyAdapter
at android.widget.ListView.removeFooterView(ListView.java:381)
How can this happen? What does removing a footer have to do with class cast exception????
The list is a multi-list adapter perhaps that is why but still a class cast exception for removing a footer (sic).
Add your footer view to ListView before calling setAdapter() method.
Added:
public void addFooterView (View v)
Since: API Level 1
Add a fixed view to appear at the bottom of the list.
If addFooterView is called more than once, the views will appear in the order they were added. Views added using this call can take focus if they want.
NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplied cursor with one that will also account for header and footer views.
Parameters
v The view to add.
Source
Also you can check this interesting post.
Hope this helps.
This is some code for the answer above, it worked in my case:
I had to set a footerView (it's a loadingView in a listView with pagination) to my listView before setting it's adapter and then remove it. First I initialized my loadingView from a layout file in OnCreate method:
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
loadingView = layoutInflater.inflate(R.layout.loading_view, null);
Then I used this workaround in the same method:
this.setIsLoading(true);
listView.setAdapter(adapter);
this.setIsLoading(false);
Where
private void setIsLoading(boolean isLoading)
{
this.isLoading = isLoading;
if (isLoading) {
listView.addFooterView(loadingView);
}
else {
listView.removeFooterView(loadingView);
}
}
The problem does not come from removeFooterView(), but from addFooterView().
If you read the documentation, it states that an wrapper will be added to your adapter:
If the ListView's adapter does not extend HeaderViewListAdapter, it will be wrapped with a supporting instance of WrapperListAdapter.
Thus you must use the getter for retrieving the wrapped adapter and cast it to your adapter. Like this:
((MyAdapter) ((HeaderViewListAdapter) listView.getAdapter()).getWrappedAdapter())
Hope this will help you with your issue.
Best regards,
Adding to the other answers, if you're adding/removing footers dynamically (such as if they reach the bottom of your list and then you're adding a footer view) the easiest thing is to Override setAdapter in your ListView and add a new View object as the footer there, this will ensure the adapter is wrapped in the HeaderViewListAdapter:
#Override
public void setAdapter(ListAdapter adapter) {
addFooterView(new View(getContext()));
super.setAdapter(adapter);
}
Related
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
I am trying to get a count of RecyclerView children. I've tried this:
myRView.getChildCount();
And this:
LinearLayoutManager lm = ((LinearLayoutManager)myRViews.getLayoutManager());
lm.getChildCount();
I need to get a child View at certain position so that's why I need this. If I call getChildAt(index) I never get any child View.
Both of these methods return 0. How else to get a child View from RecyclerView? My items appear correctly and everything is working fine. I am calling these methods after I create my adapter and set it to RecyclerView. Thank you for your help.
I assume you are calling those methods before layout is calculated.
When you set the adapter, the layout will happen in the next view tree traversal. You can consider adding a ViewTreeObserver.
You could use your adapter getItemCount() function.
myRView.getAdapter.getItemCount();
The function is called when the view is not ready that's why it returns zero, use post() method will help.
myRView.post(new Runnable() {
#Override
public void run() {
Log.show("myRView.post " + myRView.getChildCount());
View childView = myRView.getChildAt(0);
}
});
getChildCount() may return 0 if you forget to set LayoutManager to RecyclerView.
myRView.setLayoutManager(mLayoutManager);
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 have a ListFragment that uses a header view. Both the header's contents and the list's are fetched from a background task. In order to not re-fetch the data on configuration changes, I am calling setRetainInstance and keeping the data on the fragment.
When the the configuration changes, the view is recreated, so it removes the header view that I previously populated. Since now I already have the data, I should just re-add the header view to the list.
Unfortunately when I try doing this... boom!
java.lang.IllegalStateException: Cannot add header view to list -- setAdapter
has already been called.
Apparently, even tho the view is destroyed and onCreateView is called again, the list's adapter is already set (or the state is retained), making it impossible to add the header view again.
How can I keep the ListView's header or redraw it without recreating the fragment on orientation changes?
This is intended behaviour, take a look at the Android source code here for guidance on API 17, but really any will do. The relevant part is:
Add a fixed view to appear at the top of the list. If addHeaderView is
called more than once, the views will appear in the order they were
added. Views added using this call can take focus if they want. NOTE:
Call this before calling setAdapter. This is so ListView can wrap the
supplied cursor with one that will also account for header and footer
views.
public void addHeaderView(View v, Object data, boolean isSelectable) {
if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {
throw new IllegalStateException(
"Cannot add header view to list -- setAdapter has already been" +
"called."); // Edit: SK9 wrapped this.
}
FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
// in the case of re-adding a header view, or adding one later on,
// we need to notify the observer
if (mAdapter != null && mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
The adapter is not null when you come to add the header again and an exception is being raised. To resolve your issue, something along the following lines will do just fine:
setListAdapter(null);
getListView().addHeaderView(mHeader);
setListAdapter(new MyAdapter(getActivity(), items));
I wouldn't even classify this as a workaround. I encountered the same problem and this worked for me.
Apparently footers are treated very differently, see here:
public void addFooterView(View v, Object data, boolean isSelectable) {
// NOTE: do not enforce the adapter being null here, since unlike in
// addHeaderView, it was never enforced here, and so existing apps are
// relying on being able to add a footer and then calling setAdapter to
// force creation of the HeaderViewListAdapter wrapper
FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mFooterViewInfos.add(info);
// in the case of re-adding a footer view, or adding one later on,
// we need to notify the observer
if (mAdapter != null && mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
it's a know issue, but you can resolve it like this:
add header before the set adapter and remove him
Yes, it's a known issue, but can be avoided with the proper approach.
It seems that a solution similar to your problem exists.
These guys found a workaround: setSelected in OnItemClick in ListView
Hope it helps ;)
I need to show ListView header always, even when ListView has no items.
It is possible to do? Or better add header in ListView as first item?
If there's no elements for list and you are not adding the adapter, just add this:
mListView.setAdapter(null);
and the header will appear.
In your activity in onCreate You can add header by adding code:
View headerView = ((LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.header_view, null, false);
getListView().addHeaderView(headerView);
In most cases no need to add header, You can just add items in xml layout.
As case you can use http://viewpagerindicator.com/
and set getListView().setEmptyView(emptyView); // when your listView has no items
My solution was to manually toggle the empty view.
/**
* Custom empty view handling because we don't want the
* list to be hidden when the empty view is displayed,
* since the list must always display the header.
*/
private void toggleEmptyView(Adapter adapter)
{
final View emptyView = findViewById(R.id.empty_view);
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
emptyView.setVisibility(adapter.getCount() == 0 ? View.VISIBLE : View.GONE);
}
});
}
Irrespective of whether your ListView has elements or not, header will be visible always. If there are elements in ListView, header will scroll along with them else it will be on top always.
For how to add header view to ListView, you can refer other answers provided by users.