in my listview I have items with different layouts, in fact they use one sub-layout few times. I cannot use getViewTypeCount() and getItemViewType(), because I don't know how many times the sublayout will be used. Is it possible to optimize somehow getView() method and use it's convertView parameter, or do I have to inflate view each time?
Since you know how many types of layout you would have - it's possible to use those methods.
getViewTypeCount() - this methods returns information how many types of rows do you have in your list
getItemViewType(int position) - returns information which layout type you should use based on position
Then you inflate layout only if it's null and determine type using getItemViewType.
Look at this tutorial for further information.
UPDATE:
To achieve some optimizations in structure that you've described in comment I would suggest:
Storing views in object called ViewHolder. It would increase speed because you won't have to call findViewById() every time in getView method. See List14 in API demos.
Create one generic layout that will conform all combinations of properties and hide some elements if current position doesn't have it.
I hope that will help you. If you could provide some XML stub with your data structure and information how exactly you want to map it into row, I would be able to give you more precise advise
Related
I have decided to upgrade my code to use RecyclerView now instead of the list I am using now.
As I understand the following is how it normally goes:
onCreateViewHolder - this inflates a view, and does the findviewbyid and returns it as a ViewHolder object for the view
onBindViewHolder - this assigns the view holder values to the position view (which is being recycled).
This is all fine and dandy... If the views in the list contain the same fields...
My views however in my list are different, before I programmatically added views depending on the adapter List (in the getView method).
Is there a "good practice" way to handle this, I can't think of a good way to get around this.
getViewItemType does not work as the views are unique and that they are not predefined.
This is what you need to use when you different types of Views inside a ListView or RecyclerView :-
getItemViewType() and getViewTypeCount()
First you need to use getViewTypeCount() and return the number of unique views you need inside your List. Then override getItemViewType() and return the View type you want to inflate inside the List row.
Hope it will help.
If you still have any issue and need a working example, let me know, i'll update my answer.
I'm new at Android programming and I'm stuck in a situation for two days that I can't seem to solve.
I've got a ListActivity that should be populated with two different views that has almost no simularity. Untill now I've used MergeAdapter and it worked fine but my outcome was like this:
Adapter1,Adapter2. and I didn't have the ability to change the order of the items coming to the list.
My question is: is it possible to create an adapter that is holding items of two views and not adapters of two views so I'll have my items sorted by the way I input them?
For simplicity sake, I got an ArrayList of those two items and each has "int position" so I'll be able to insert them into the list sorted by position.
EDIT: I've tried extending BaseAdapter but once again I need two adapters as I've read online but if I do so, I won't be able to control the place of an item on the list.
I hope I'm more clear this time.
Welcoming any response.
Thank you.
You can subclass BaseAdapter and utilize the following methods:
getItemViewType(int position)
getViewTypeCount()
getViewTypeCount() should return the number of different row types your adapter supports. getItemViewType() is where you implement the "decision" of which view type a particular row should have. If, for example, getViewTypeCount() returns 3, then getItemViewType() method should return 0, 1, or 2.
You can use this inside of getView to inflate/create a different layout for different row types.
EDIT:
Since it's a custom adapter, you can implement it in whatever way makes sense for your data. If you can create a data structure that works for what you want, then just make the adapter able to work with that. In the worst case, you might just have an array (or list) of Objects and have to use instanceof to do the decision work.
I am having some difficulty in getting my implementation of a BaseAdapter working to populate a GridView.
I've a few questions around the workings of the BaseAdapter, based on the example here: http://developer.android.com/resources/tutorials/views/hello-gridview.html
In my implementation, my BaseAdapter.getCount() method returns 130. Therefore I would have expected the getView() method to be invoked once for each count. However, as far as I can see getView() is only invoked approximately 70 times....why is this?
If getView() is used to construct the View object at each position in the grid, then what is the purpose of getItem() which returns an Object?
Lastly, I wish my grid to be 10 columns wide and 13 rows in height. To achieve this, do I just set the android:numColumns attribute to be 10?
Any help is appreciated in understanding this.
Thanks.
However, as far as I can see getView() is only invoked approximately 70 times....why is this?
It generates the views as they are rendered to the screen
If getView() is used to construct the View object at each position in the grid, then what is the purpose of getItem() which returns an Object?
getItem(int position)
Get the data item associated with the specified position in the data set.
As the description says, it returns the underlying data associated with that position as opposed to the View for the same position.
To achieve this, do I just set the android:numColumns attribute to be 10?
android:numColumns setNumColumns(int) Defines how many columns to show.
The description is quite explicit here.
BTW, this last question is one that you could easily test yourself rather than asking here...
Can somebody in plain words explain me the usage of getViewTypeCount() and getItemViewType() methods of ArrayAdapter?
These handle the case where you want different types of view for different rows. For instance, in a contacts application you may want even rows to have pictures on the left side and odd rows to have pictures on the right. In that case, you would use:
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
return position % 2;
}
The framework uses your view type to decide which views to hand you via convertView in your getView method. In other words, in the above example, your even rows will only get recycled views with pictures on the left side to reuse, and odd rows will only get ones with pictures on the right.
If every row in your list has the same layout, you don't need to worry about view types. In fact, BaseAdapter.java provides a default behavior for all adapters:
public int getItemViewType(int position) {
return 0;
}
public int getViewTypeCount() {
return 1;
}
This indeed provides you with the same view type for every row.
Edit - to outline the general flow:
You bind data to your AdapterView using an adapter.
The AdapterView tries to display items that are visible to the user.
The framework calls getItemViewType for row n, the row it is about to display.
The framework checks its recycled views pool for views of row n's type. It doesn't find any because no views have been recycled yet.
getView is called for row n.
You call getItemViewType for row n to determine what type of view you should use.
You use an if/switch statement to inflate a different xml file depending on which view type is required.
You fill the view with information.
You return the view, exiting getView, and your row's view is displayed to the user.
Now, when a view is recycled by scrolling off the screen it goes into a recycled views pool that is managed by the framework. These are essentially organized by view type so that a view of the correct type is given to you in convertView parameter in your getView method:
The framework again calls getItemViewType for the row it wants to display.
This time, there is a view in the recycled pool of the appropriate type.
The recycled view is passed to you as the convertView parameter to your getView method.
You fill the recycled view with new information and return it.
If we need to show different type of view in list-view then its good to use getViewTypeCount() and getItemViewType() in adapter instead of toggling a view View.GONE and View.VISIBLE can be very expensive task inside getView() which will affect the list scroll.
Please check this one for use of getViewTypeCount() and getItemViewType() in Adapter.
Link : the-use-of-getviewtypecount
Watch Outttt!!!!
I had to face for a problem implementing a ListView yesterday and it's two types of views for rows got jumbled just after I scroll it. Even though the top voted answer within this thread gives a good general explanation it hasn't highlighted the most important bit of information to stop the above UI bug which I have mentioned.
Here is my explanation:
Both getViewTypeCount() and getItemViewType() are being used by BaseAdapter's getView method to find out which type of a view should it be fetch, recycled and returned. (as explained in the top answer within the thread). But if you don't implement these two methods intuitively according to the Android API Doc, then you might get into the problem I mentioned about.
Summarized Guideline for the implementation:
To implement multiple types of Views for ListView's rows we have to essentially implement, getItemViewType() and getViewTypeCount() methods. And getItemViewType() documentation gives us a Note as follows:
Note: Integers must be in the range 0 to getViewTypeCount() - 1.
IGNORE_ITEM_VIEW_TYPE can also be returned.
So in your getItemViewType() you should return values for the View Type, starting from 0, to the last type as (number of types - 1). For example, let's say you only have three types of views? So depending on the data object for the view, you could only return 0 or 1 or 2 from the getItemViewType() method, like a zero-based array index. And as you have three types of views used,
your getViewTypeCount() method must return 3.
In any case if you return any other integer values like 1, 2, 3 or 111, 222, 333 for this method you definitely might experience the above UI bug which you just placed by not obeying to the Android API Doc.
If you didn't get the clue or couldn't still resolve and need further information please read my detailed answer within this StackOverflow Q&A thread.
Read the Android Developer Doc for further information you might be find the clue directly.
Hope this answer might be helpful to someone out there to save a lots of hours!!!
Cheers!!!
I want to generate a ListView that has some dividers between some of the entries, like it can be seen in some of the property sections. See the example below. I try to generate a List that consists of some textviews followed by one of the fancy dividers explaining the next part of the list and then again some text views. How can this be done? I thought about creating different views to add to the list? Is this the way to go?
I got a solution. I don't know if it is the best one.
I use a custom adapter derived from ArrayAdapter for the list as described in this tutorial. In the adapter class I check if the position in the getView method is a normal row, then I inflate the row layout. If it is the first row from a new group I inflate a headline layout that is a normal row plus the group headline above it.
If you don't want to mix the header into one of your rows. Consider the following solution:
You can overwrite the two methods getItemViewType and getViewTypeCount.
You now have a list that can display different rows. You need to check the expected view type for the item in the getView Method and inflate different layouts depending on it.
The list will handle the recycling for you in a way that it will return only correct recycle views to your getView method, this means if the recycleView is not null it can be used to display your current cell.
You can use my SectionedAdapter, if GPLv3 is acceptable (licensed that way due to some upstream code). You can use my MergeAdapter, if you need something more flexible and with a less-limiting license (Apache 2).
I think you might be looking for android.widget.ExpandableListView
http://developer.android.com/reference/android/widget/ExpandableListView.html
I'm also interested in an answer to this. There must be a more straightforward way to do this.
In looking at the Adapter, there's a method, Adapter.getItemViewType(int position).
ListView defines a return value, ITEM_VIEW_TYPE_HEADER_OR_FOOTER which indicates if the returned item is a header or footer.
I haven't tried it, but I assume if you create your own Adapter and return an item with the type indicating it is a header or footer, that the ListView will display it appropriately.