getViewTypeCount and getItemViewType methods of ArrayAdapter - android

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!!!

Related

Android RecycleView: Adding dynamic views

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.

Cancelling ListView's recycler and/or clearing the recycler?

I have a ListView in my app that is used to show a list with 2 types of items. The way it is currently implemented is that I have two different XML layouts for each of the item types, my adapter correctly reports the type and in the getView() method I inflate the appropriate XML according the the type in the specified position.
The problem is that in the vast majority of cases the structure of the list of items is that most of the type 1 items are in the beginning and most of the type 2 items are in the end, so usually at first you see mostly type 1 items, you scroll down and at some point you start seeing type 2 items, and they continue until the end of the list.
All works fine while I scroll until I hit that midpoint. Around that point all the calls to getView() get null passed as the convertView parameter. This makes sense obviously. The problem is that is seems like ListView stores all the previous type 1 views in the recycler, and I will not use them as long as I keep scrolling down since from now on most of the views will be type 2 views.
The views are pretty complex, with custom background and bitmaps on top of it, so I end up with lots of views in memory that I will probably never use.
My question is twofold:
Should I even worry about it? right now I am not in the point where I get OOM exceptions, but will I ever get there or is ListView smart enough to "let go" of some of those views when resources get tight?
If I do need to worry about it, is there a way to explicitly tell ListView to clear up it's recycler, or even disable it somehow?
A possible solution is to use the same XML for both layouts, have two ViewGroups in there and just set the visibility of one of them to GONE, but it seems like a waste to have a fairly complex view hierarchy if I am never going to show it.
Should I even worry about it?
No, as the user is perfectly capable of scrolling up, thereby returning to type 1 rows.
right now I am not in the point where I get OOM exceptions, but will I ever get there or is ListView smart enough to "let go" of some of those views when resources get tight?
Once you start getting OutOfMemoryError messages, this ListView will not be your problem. You only have so many row View structures, and all should be really cheap from a memory consumption standpoint.
One suggestion to deal with two different type of child view in Adapter is using getViewTypeCount method and let the adapter know actually you use two different type of view.
The listView maintains each recycler per each view type (in your case, the number will be 2), so you don't worry to any OOM exceptions and don't need to tell ListView to clear up it's recycler.
For more detailed description,
Check: getViewTypeCount and getItemViewType methods of ArrayAdapter
Code snippet for implementation:
public class SampleAdapter extends ArrayAdapter<String> {
...
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
//the result must be in the range 0 to getViewTypeCount() - 1.
if( position < 10 )
return 0;
else
return 1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
switch( getItemViewType(position) ){
case 0:
//do something for type1 view.
break;
case 1:
//do something for type2 view.
break;
}
return convertView;
}
}
I would not worry too much when having only 2 view types.
If you want to optimize it, I suggest not having a very complex layouts and instead use custom View and do drawing of the Bitmaps yourself. A bit more complex task, but will bring better UX when going through midpoint.

Android - ListView Adapter with items of two views

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.

Using BaseAdapter to populate GridView

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...

How to optimizie ListView with different item's layout

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

Categories

Resources