1

Developing my very first app I'm trying to add sections to my elements in a list view. All items a have a date and I want to return a simple layout containing a date each time the date changes. In my adapter I have the following:

    public View getView(int position, View convertView, ViewGroup parent) {
    Match match = matchArrayList.get(position);
    Calendar matchTime = match.getDate();
    SimpleDateFormat date = new SimpleDateFormat("dd-MM-yyyy");
    SimpleDateFormat time = new SimpleDateFormat("HH:mm"); 
    String sDate = date.format(matchTime.getTime());
    SeparatorHolder separatorHolder = null;
    MatchHolder matchHolder = null;

    if (convertView == null) {
        if (!sDate.equals(_lastDate)) {
            convertView = inflator.inflate(R.layout.date_separator, null);
            separatorHolder = new SeparatorHolder();
            separatorHolder.Date = (TextView) convertView.findViewById(R.id.date);
            convertView.setTag(separatorHolder);
        } else {
            convertView = inflator.inflate(R.layout.match_layout, null);
            matchHolder = new MatchHolder();
            matchHolder.Time = (TextView) convertView.findViewById(R.id.time);
            matchHolder.HomeTeam = (TextView) convertView.findViewById(R.id.homeTeam);
            matchHolder.AwayTeam = (TextView) convertView.findViewById(R.id.awayTeam);
            matchHolder.HomeTeamImage = (ImageView) convertView.findViewById(R.id.homeTeamImageView);
            matchHolder.AwayTeamImage = (ImageView) convertView.findViewById(R.id.awayTeamImageView);
            matchHolder.TournamentImage = (ImageView) convertView.findViewById(R.id.tournamentImageView);
            matchHolder.TVChannelImage = (ImageView) convertView.findViewById(R.id.tvChannelImageView);
            convertView.setTag(matchHolder);
        }
    } 
    else {
        if (!sDate.equals(_lastDate)) 
            matchHolder = (MatchHolder) convertView.getTag();
        else
            separatorHolder = (SeparatorHolder) convertView.getTag();
    }

    if (!sDate.equals(_lastDate)) {
        _lastDate = sDate;
        separatorHolder.Date.setText(sDate);
    } else {
        UrlImageViewHelper.setUrlDrawable(matchHolder.TournamentImage, match.getTournamentImage());
        UrlImageViewHelper.setUrlDrawable(matchHolder.HomeTeamImage, match.getHomeTeamImage());
        matchHolder.HomeTeam.setText(match.getHomeTeam());
        UrlImageViewHelper.setUrlDrawable(matchHolder.AwayTeamImage, match.getAwayTeamImage());
        matchHolder.AwayTeam.setText(match.getAwayTeam());
        matchHolder.Time.setText(time.format(matchTime.getTime()));
        UrlImageViewHelper.setUrlDrawable(matchHolder.TVChannelImage, match.getTVChannelImage());
    }

    return convertView;
}

Everything works just fine until I reach the very last line:

return convertView;

Adding a break point to that line and trying to step passed it immediately throws some sort of error.

Now being new to Android and Eclipse I really can't find a stacktrace similar to what I get when coding .Net in Visual Studio. All I can see is that in the Debug perspective in Eclipse a tab with AbsListView.class is opened...

Can anyone make any sense of what I'm trying to achieve? And maybe help out a bit? I looked at this link and as far as I can tell he also returns two different views depending on item type :-?

Edit: Implemented Streets Of Bostons answer and changed the code to

@Override
public int getItemViewType(int position) {
    Match match = matchArrayList.get(position);
    if (match.HomeTeam == "") {
        return 0;
    }
    else {
        return 1;
    }
}

Now it works but scrolling in my list FC's my app

Thanks in advance

Ranjit
  • 5,130
  • 3
  • 30
  • 66
CJe
  • 1,928
  • 3
  • 24
  • 53

2 Answers2

12

There is not enough info in your questions. However, i'll try my best :-)

If you return more than one (type of) View (R.layout.date_separator or R.layout.match_layout), you have to implement the adapter's getViewTypeCount and getItemViewType methods:

@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    Match match = matchArrayList.get(position);
    ...
    ...
    if (!sDate.equals(_lastDate)) {
        return 0; // matches R.layout.date_separator
    }
    else {
        return 1; // matches R.layout.match_layout
    }
}

It has to do with the recycling of Views. When convertView != null, you have to make sure that the parameter convertView matches the original inflation of the convertView done at an earlier time. The method getItemViewType makes sure of that.

Here is a suggested getView implementation:

  • The inflation of the convertView is not entirely driven by getItemViewType
  • Switched the if and else in the second if statement (SeparatorHolder and MatchHolder were switched in calling convertView.getTag)

.

public View getView(int position, View convertView, ViewGroup parent) {
    Match match = matchArrayList.get(position);
    Calendar matchTime = match.getDate();
    SimpleDateFormat date = new SimpleDateFormat("dd-MM-yyyy");
    SimpleDateFormat time = new SimpleDateFormat("HH:mm"); 
    String sDate = date.format(matchTime.getTime());
    SeparatorHolder separatorHolder = null;
    MatchHolder matchHolder = null;

    int itemType = getItemViewType(position);
    if (convertView == null) {
    if (itemType == 0) {
        convertView = inflator.inflate(R.layout.date_separator, null);
        separatorHolder = new SeparatorHolder();
        separatorHolder.Date = (TextView) convertView.findViewById(R.id.date);
        convertView.setTag(separatorHolder);
    } else {
        convertView = inflator.inflate(R.layout.match_layout, null);
        matchHolder = new MatchHolder();
        matchHolder.Time = (TextView) convertView.findViewById(R.id.time);
        matchHolder.HomeTeam = (TextView) convertView.findViewById(R.id.homeTeam);
        matchHolder.AwayTeam = (TextView) convertView.findViewById(R.id.awayTeam);
        matchHolder.HomeTeamImage = (ImageView) convertView.findViewById(R.id.homeTeamImageView);
        matchHolder.AwayTeamImage = (ImageView) convertView.findViewById(R.id.awayTeamImageView);
        matchHolder.TournamentImage = (ImageView) convertView.findViewById(R.id.tournamentImageView);
        matchHolder.TVChannelImage = (ImageView) convertView.findViewById(R.id.tvChannelImageView);
        convertView.setTag(matchHolder);
    }
    } 
    else {
        if (itemtype == 0) 
            separatorHolder = (SeparatorHolder) convertView.getTag();
        else
            matchHolder = (MatchHolder) convertView.getTag();
    }

    if (itemType == 0) {
    _lastDate = sDate;
    separatorHolder.Date.setText(sDate);
    } else {
    UrlImageViewHelper.setUrlDrawable(matchHolder.TournamentImage, match.getTournamentImage());
    UrlImageViewHelper.setUrlDrawable(matchHolder.HomeTeamImage, match.getHomeTeamImage());
    matchHolder.HomeTeam.setText(match.getHomeTeam());
    UrlImageViewHelper.setUrlDrawable(matchHolder.AwayTeamImage, match.getAwayTeamImage());
    matchHolder.AwayTeam.setText(match.getAwayTeam());
    matchHolder.Time.setText(time.format(matchTime.getTime()));
    UrlImageViewHelper.setUrlDrawable(matchHolder.TVChannelImage, match.getTVChannelImage());
    }

    return convertView;
}
Streets Of Boston
  • 12,576
  • 2
  • 25
  • 28
  • Thanks for a super quick and absolutely spot on answer :-) Now it works! – CJe Feb 28 '13 at 15:27
  • No problem :) I am a bit worried about the '_lastDate'. It could mess things up, because it makes getItemViewType's return value not only based on the value of 'position', but on the value of '_lastDate' as well. If this doesn't exactly match with what happens in 'getView(...)', you still may run into problems. – Streets Of Boston Feb 28 '13 at 15:29
  • It works as far as rendering the list but as soon as I start scrolling down it force closes. Any thoughts on that? It worked just fine with only one view type... – CJe Feb 28 '13 at 15:53
  • That's problem i feared would happen with '_lastDate' that I described in my comment earlier. – Streets Of Boston Feb 28 '13 at 15:57
  • Changed my code - should that be appropriate? See edit in OP. It still FC's – CJe Feb 28 '13 at 16:05
  • 1
    Your getItemViewType doesn't match the getView. I'll update my answer with more info. – Streets Of Boston Feb 28 '13 at 16:18
  • Thanks for the update. Am I correct in assuming that it's rather "best practice" to let the getItemViewType(position) determine the returned view type in the getView(...) method? – CJe Feb 28 '13 at 16:37
  • Yes, or be absolutely sure they'll 'match'. – Streets Of Boston Feb 28 '13 at 16:45
  • Everything works like a charm! Now I can start focusing on scroll performance :-) Thanks a million Boston. Cheers ;-) – CJe Feb 28 '13 at 16:46
0

I see that the question is closed, but you should use equal method for String comparison like this match.HomeTeam == "". Have a look at this answer for further infomation

Community
  • 1
  • 1
nlt
  • 555
  • 7
  • 11