Entering both if AND else statement?
So I've got this code (updated for solution).
@Override
public View getView(int position, View convertView, ViewGroup parent) {
...
final Direction d = directions.get(position);
if (d != null) {
TextView direction = (TextView) row.getTag(R.id.directionTextView);
TextView departure1 = (TextView) row.getTag(R.id.departure1);
TextView departure2 = (TextView) row.getTag(R.id.depa开发者_开发技巧rture2);
TextView departure3 = (TextView) row.getTag(R.id.departure3);
direction.setText(d.getName());
if (d.getTimeStamps().size() == 0) {
departure1.setText(R.string.nodepartures);
departure1.setTextColor(R.color.grey);
} else {
for (int i = 0; i < d.getTimeStamps().size(); i++) {
switch (i) {
case 0:
departure1.setText(d.getTimeStamps().get(i));
break;
case 1:
departure2.setText(d.getTimeStamps().get(i));
break;
case 2:
departure3.setText(d.getTimeStamps().get(i));
break;
default:
break;
}
}
}
}
return row;
}
}
The problem I was having was that one of the TextViews would turn grey when it wasn't supposed to. I tried fixing it by always setting the text to black again, but that turned every single one of them grey. Until I tried:
setTextColor(context.getResources().getColor(R.color.black));
instead of just
setTextColor(R.color.black);
Don't know why the latter works when setting text grey, but there it is. I guess I'm just a little retarded. :)
What you think is happening simply cannot happen (*
, **
). What you need to do is prove to yourself that it is not happening.
I'd do this by adding some traceprints to the code. Put one before the if
statement, one at the starts of the "then" and "else" clauses, and one after the if statement. Then run it. I expect that this will reveal that the if
statement is actually being run twice, and running the "then" clause the first time and the "else" clause the second time.
(* In theory, it might happen if there was a serious bug in the emulator. But you should only consider that as a possibility if you have irrefutable evidence.)
(** Another possibility is that there might be a significant difference between the sample code above and the actual code you are testing. It happens ...)
AsLanFromNarnia is on the right track. ListView recycles its child views. You can never assume that convertView
is in any sort of default state for its type. Set every relevant field every time getView
is called. In your case it means setting the text color when you set the text.
There is another way to handle cases like this where you want to have heterogenous lists: use view types. Your adapter can return the number of types you have for getViewTypeCount
and then report the type of each item from getItemViewType
. If you do this, you will always get a convertView
passed into your getView
method of the proper type, alleviating the need to change otherwise static layout each time.
Hmm... I can't see how that would happen. Are you sure your brackets are in the right place? Does it still occur if you switch the statement around?
I agree with Aircule! This code is pretty nutty! How about this?
if(d.getTimeStamps().isEmpty())
{
departure1.setText(R.string.nodepartures);
departure1.setTextColor(R.color.grey);
}
else
{
departure1.setText(d.getTimeStamps().get(0));
departure2.setText(d.getTimeStamps().get(1));
departure3.setText(d.getTimeStamps().get(2));
}
It should do the exact same thing an it's a lot less complicated. Also, let's say you run this code once and the list is empty, so you set the color of departure1 to gray and run it again. This time you get data and fill in the items, but you never change the color of departure1, so it will stay gray. Similarly, if you take that scenario the other way around, you don't empty the TextViews
when the list is empty. Another tip, if there are only ever going to be three items (or any small fixed number of items) then you're probably better off just using a normal layout instead of a list. That way you won't have to go through making a custom adapter, you can just call the items by name.
Have you set a default color or styling in your layout XML file that is loaded by LayoutInflator?
I believe it's turning gray because at some point in your program the method is being called with 0 timestamps.
It only has to happen once for it to set the departure1.textColor attribute, then it will persist until changed back.
You mentioned you tried setting it to black in the else statement but it turned everything gray. This doesn't make sense at all. Try adding the command to turn text to black at each case statement, so:
case 0:
departure1.setTextColor(R.color.black);
departure1.setText(d.getTimeStamps().get(i));
break;
case 1:
departure2.setTextColor(R.color.black);
departure2.setText(d.getTimeStamps().get(i));
break;
case 2:
departure3.setTextColor(R.color.black);
departure3.setText(d.getTimeStamps().get(i));
break;
Based on what you describe we can only give hints at best.
- Are you sure you recompiled all your code? I have seen debugging yield funny results because part of code was not in synch with the bytecode beng debugged
- Is this an event based system? Could it be that your code is called twice, once with teh empty list followed directly by the list with 1 entry after that entry is added to the list?
As code improvement I would do the following to refactor the switch
(assumption here is the control type is Text
which is probably wrong but easily fixed):
if (d.getTimeStamps().isEmpty()) {
departure1.setText(R.string.nodepartures);
departure1.setTextColor(R.color.grey);
} else {
Text[] fields = new Text[] { departure1, departure2, departure3 };
for (int i = 0; i < fields.length && i < d.getTimeStamps().size(); i++) {
fields[i].setText(d.getTimeStamps().get(i));
fields[i].setTextColor(R.color.black);
}
}
update
Seeing that you do not set the color for departure values, I think you assume that the lines are freshly created when this code runs. If that assumption is incorrect, your situation might be that a line that previously held a 'no departure' line, now gets re-used for a departure line therefore inheriting the grey color.
精彩评论