So, I am making this application. The application parses a website, or more specifically a vbulletin-board. When I'm parsing a thread in the forum, I have divided it up so that when I parse each post in that thread, I get the actual content of the post in sections such as this, and I store the sections in the correct order in an array:
[Plain text]
[Quote from somebody]
[Plain text]
[Another quote]
[Another quote again]
[Some more plain text]
However, a post can be arranged in any order as you might know, and can consist of more or fewer sections than in the example, and it doesn't have to have quotes in it either, or it might just be one or several quotes. Anything is possible.
When I list the posts in my application, I am using a ListView. Each row of this listview will then always consist of a header, and any combination of the previously mentioned sections.
The way I was thinking of doing it after googling a bit about it is to have one "Base-layout" with just a layout-tag in one XML-file, and a separate layout for each section, stored in separate XML-files, and at each call to getView() in my adapter, look at the post at that position in my "Post-list", and then loop through the sections in that particular post, and inflate a new "Quote-layout" for each quote-section stored in the post, and inflate a "Plain-text-layout" for each plain-text-section in the post. And for each of those I fill in all the content belonging to that post.
I think this would work, but there might be a performance problem? As I understand it layout inflation is quite expensive, and I won't be able to recycle the View passed in to getView() either, since it might have a bunch of sections added to it that I might not need in another call to getView().. That is, if I understand getView() and the recycling somewhat.
This is a basic example of what I mean with the getView() method of the adapter:
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
// Inflate the base-layout, which the others are added to.
view = mInflater.inflate(R.layout.forum_post,null);
View header = mInflater.inflate(R.layout.post_header_layout, null);
View message = mInflater.inflate(R.layout.post_text_layout, null);
View quote = mInflater.inflate(R.layout.post_quote_layout, null);
((ViewGroup)view).addView(header);
((ViewGroup)view).addView(message);
((ViewGroup)view).addView(quote);
return view;
}
And then inflate more quote-views/message-views as needed when I extract the data from my list of saved posts.
The base-layout is just a LinearLayout-tag
The layouts I inflate are just RelativeLayouts with some TextViews and an ImageView added.
This code produces this result, where I have a Header with username, picture, etc.., One section of Plain text, and one Quote-section. This doesn't seem to work properly all the time though, because when I tried it out just now a copy of the list seemed to get stuck on the background and another one scrolled on top of it..
http://s14.postimg.org/rizid8q69/view.png
Is there a better way to do this? Because I imagine this isn't very efficient
You need to override getViewItemType
and getViewTypeCount
.
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
.
Example :
private static final int TYPE_ITEM1 = 0;
private static final int TYPE_ITEM2 = 1;
private static final int TYPE_ITEM3 = 2;
@Override;
public int getItemViewType(int position)
{
int type;
if (position== 0){ // your condition
type = TYPE_ITEM1; //type 0 for header
} else if(position == 1){
type = TYPE_ITEM2; //type 1 for message
}else {
type = TYPE_ITEM3; //type 2 for Quote
}
return type;
}
@Override
public int getViewTypeCount() {
return 3; //three different layouts to be inflated
}
In getView
int type= getItemViewType(i); // determine type using position.
switch (type) {
case TYPE_ITEM1:
view= mInflater.inflate(R.layout.post_header_layout, null); // inflate layout for header
break;
case TYPE_ITEM2:
view = mInflater.inflate(R.layout.post_text_layout, null); // inflate layout for quote
break;
case TYPE_ITEM3:
quote = mInflater.inflate(R.layout.post_quote_layout, null); // inflate layout for message
break;
....
You need to use a View Holder for smooth scrolling and performance.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
You can check the tutorial below
First of all you want to reuse convertView
that has been passed as one of the argument. This way you can avoid inflating the item View
.
Secondly, you could use something as ViewHolder
to store references to your inner View
s. Using ViewHolder
will increase performance whether you are inflating view or finding them by id as both methods are very expensive.
Set the ViewHolder
as a Tag on item View
.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder;
// if possible reuse view
if (convertView == null) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(resource, parent, false);
viewHolder = new ViewHolder(mInflater.inflate(R.layout.post_header_layout, null));
view.setTag(viewHolder);
} else {
// reuse view
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
//set text, listeners, icon, etc.
return view;
}
The ViewHolder
is just private inner class storing referenced to view.
private static class ViewHolder {
private final View view;
private ViewHolder(View view) {
this.view = view;
}
}
Talk about ListView
usage was given at Google IO 2010.
The inflater needs to know the real type of the futur parent ViewGroup, therefore the following code is erroneous:
view = mInflater.inflate(R.layout.forum_post,null);
and instead, you should use this one:
view = mInflater.inflate(R.layout.forum_post,viewGroup,false);
Same thing for the other inflate
: use the real parent (view
in this case) or another viewGroup which is of the same type as the (futur) parent; otherwise the LayoutParameters will not be set to the right type and the values that you have specified in your XML code will be lost (never used).
来源:https://stackoverflow.com/questions/17370525/listview-adapter-with-arbitrary-number-of-row-types-dont-know-the-number-of-di