Here is the problem i am facing. I am developing a custom list view in which a single list view item is consisted of multiple text and image views. But depending on the item properties it sometimes needs to have 4 TextViews sometimes 1, sometimes 6.... the number is dynamic and i am having trouble figuring out how to developed a proper view holder pattern that will work.
I can not solve the problem by creating a number of TextViews and hiding them and displaying when necessary, since i dont know how many of them are necessary per item.
And inflating them dynamically and adding to the layout every time in getView is disastrous to say the least :(
Is it a viable solution to have an array list of Views in the holder and then work something out?
I'd recommend using the adapters view types: getItemViewType() and getViewTypeCount()
The number of view types depends on how many permutations are needed to represent all the varying ways an individual list item will look.
So if there are 4 different UI looks, then you'd have 4 different view types. You'd then have a ViewHolder representing each type. Then in the getView(), you just detect which type is represented by the position and inflate/populate as needed. You won't need to worry about hiding different portions of the UI to change up the look. The adapter will ensure you are only given a recycled view for the proper type.
For a nice detailed explanation of using the view type, check out this post.
Related
I can't fully understand getItemViewType(), I searched on the internet and every search tells how to use it but no one is telling how it works. I want to know why it is used, how it works and if it comes before on create view holder and any help will be appreciated.
I searched on the internet I expected to find full explanation but I found its working.
A RecyclerView can show multiple types of items in it. For example, it can show images and videos in one recycler. These obviously would have different views to display them. This function returns the type of view this item should use to display this item. The type doesn't actually mean anything, it's just used by the recycler to pick the right type of view when it recycles them. When it calls onCreateView, it remembers the type of this item was a 1, and saves it in a pool of views for that type. When it later needs to recycle another item of type 1, it looks in that pool to see if it already has a view, and reuses it if so.
You can number them whatever you want, although using an enum and consecutive integers is generally the easiest and most maintainable path.
If your recycler view only needs to display a single type of view, its ok to just hard code this to always return 1.
I am creating a simple question and answer application that (in the future) will support showing in a single RecyclerView a big number of different questions.
Each question (for now) has a question and an answer part.
Each list item has a TextView for the question (along with some other decorative stuff) and then I have to add the answer part.
There are two ways I can go about. Add a View for each type of answer I can have (there are currently 12 type of answers, such as text, number, slider, date , date range etc) and on the ViewHolder of the RecyclerView set all non used views to "gone", or create 12 different list item layouts (which will have the question parts aswell) and pass a different viewType in the onCreateViewHolder method which will create one of 12 different ViewHolders which will extend one abstract ViewHolder which will handle the common stuff.
So can anyone tell me which of the two methods is better? Also my concern is speed (it is projected that at some point this may reach up to one thousand list items) so speed-wise what would be better?
Obvious creating different views type will be more efficient and good practice. And will make your list smoother. (as you said, will have large number of items)
Reason being.
View will only render required view. (As you have given type for items.) Thus will require less memory in UI thread.
If you include all views in RecyclerView item, they all will render (even if invisible).
Remember all stuff in layout has its class and methods. It is for sure better to render 2 classes than 10 classes.
I can't understand how the RecyclerView recycle the views and reuses them if there are more than one type of views.I know that the Adapter will create two more ViewHolders for reusing.In that case,there are no more than two type of views that can be reused to present the next item in the window.But if the type of next item doesn't match either of the two types that have been recycled,there will be no views available to be reused to present the next item because the type of view it needs is still visible on the screen and cannot not be recycled.How does the system handle it ? Any and all answers are appreciated.
If there is a recycled view available that MATCHES to the new one that's becoming visible, then it will re-use. Otherwise it'll create the new object for the new view. It uses getViewType () to find that.
You can take a look at this for few more related points.
The RecyclerView will create as many ViewHolders as it needs to fill the available visible space. Recycling happens when one scrolls out of view. At that time, it will be reused for a new item scrolling into view.
The number of ViewHolders that have been created. Typically, you can figure out how many
there should be by determining how many list items fit on your screen at once and add 2 to 4
to that number. That isn't the exact formula, but will give you an idea of how many
ViewHolders have been created to display any given RecyclerView.
In most case, we need to implement the BaseAdapter’s getItemViewType() and getViewTypeCount() for dynamic item content of the listview, as this post says. But I think this solution is only suitable for finite number and knowing beforehand, such as listview item with sending layout and receving layout.
What about the case that the listview with its item content impossible knowing beforehand?
For example, I need to show a contact list from server, the contact list size is about several thousand. For each item, I need to show, for example, the hobby “list”. It is a small range of 0 to tens of string. So in this case:
The item types is relatively bigger than normal case using “getItemViewType”
Though each item may be different, but similar to a certain degree: the item content is different in the number of views, but common in view type. Item A is different from item B only because it have more TextViews.
For each time in the getView, the convertview is hard to simply reuse because they are different, but if we create new TextView and added to the convertView, it will impact the scrolling of the listview. I don't think it's appropriate such way. What should i do in such case?
Unfortunately you cannot easily change the number of item view types on the fly. The getViewTypeCount() method is only invoked when the adapter is set on the ListView. That means, were you to dynamically change it, then you would have to call setAdapter() again. This is a huge performance hit as the ListView will toss out all the recycled views and re-generate everything from scratch again.
Honestly, it looks like you should be using an ExpandableListView instead. It allows you to displays lists of items under groups. The only difference is the groups are placed on top of the list. So where you have A, B, C, D on the left side in your picture...in the ExpandableListView it'll sit on top.
The ExpandableListView can easily handle your situation where a given grouping could have any variable number of items within it. You mentioned needing to store a contact list. I'd suggest taking a look at a RolodexArrayAdapter for use with the ExpandableListView. It may be of help.
I have a ListView and it should have four different types of items. I searched for it, found different solutions that this is possible and tried to do my stuff just like the other persons did. I've created different ViewHolders (one for each type). When the ListView appears for the first time everything is fine. But when I begin to scroll I get a classCastException.
The reason is pretty obvious:
holder = (FeedViewHolder) convertView.getTag();
My adapter tries to get the ViewHolder by getting the tag from the convertView if it's not null. But this ViewHolder seems to be the ViewHolder of the previous item so it can't be casted.
I search StackOverflow and Google but all the examples seem to work as they use the same or pretty equal ViewHolders for their different items. But my Objects really differ from each other and need different ViewHolders. Can anyone help me to solve this?
Ok a collegue just helped me:
I hadn't implemented the method getViewTypeCount. That was it. The Android system didn't knew that there different view types because I hadn't defined them. Thanks anyway to dmaxi!
Define item view types for the ListView and cast the ViewHolder based on the actual view type as the code shows in this answer: Creating ViewHolders for ListViews with different item layouts