views:

377

answers:

7

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.departure2);
            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. :)

A: 

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?

GaZ
I'm pretty sure my brackets are in the right place, but I've updated my original post with the full source for the adapter. I may be code-blind at the moment.
AmITheRWord
A: 

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.

CaseyB
Hmm, not sure this is quite the same, what if the `ArrayList` only contains 1 item?
Jake
The ArraylList can contain anywhere from 0 to exactly 3 items, depending on which row is being checked. Your code would crash my application.If I run this code once, and the list for that specific row is empty, it will still be empty if the code is run again. The list is never modified.I'll try to update my code-sample to give some more context.
AmITheRWord
In that case I would still recommend doing away with the `List` and just using a `LinearLayout`.
CaseyB
That's gonna add a lot of extra code with nested for-loops dynamically adding child-views, which the adapter takes care of for me. I'm also gonna have to surround the LinearLayout with a scrollview. If all else fails, I'll try this, but I really don't want to spend an hour extra on this.
AmITheRWord
+3  A: 

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

Stephen C
I've done that. It proves that it is not happening, so I guess I'm black/grey colorblind on certain numbers? Maybe it's synesthesia! I attached an image-link to the original post. :P
AmITheRWord
A: 

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.

rsp
Thanks for the concrete improvement suggestion. I tried cleaning and rebuilding the project even restarted eclipse and the emulator. Still no luck. I've updated my original post with the full source of the adapter. I can't see anything wrong with it, but I may be, as naikus suggested, code-blind at the moment. I'm hoping someone see's some error there.
AmITheRWord
A: 

Have you set a default color or styling in your layout XML file that is loaded by LayoutInflator?

naikus
No, I have not. Should I try setting the color to black in the XML layout?
AmITheRWord
You can try that approach
naikus
A: 

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;
Fredrick Pennachi
Yep. That turns every single textview grey. :P
AmITheRWord
Have you tried another color like red or something, just to check?
Fredrick Pennachi
+2  A: 

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.

adamp
I wouldn't be surprised if he had a typo when he tried setting it to black explicitly the first time. I further commented that he should try setting it to some color like red but unfortunately he hasn't gotten back to us yet.The screen shot he included with one field gray and two fields black makes it seem pretty improbable that it's any emulator problem but rather just a misunderstanding regarding the lifetime of the TextView objects.
Fredrick Pennachi
I tried setting it to red, but it still turned grey. But then I tried adding the context-stuff before, and it worked! So... Just some minor thing overlooked I guess, sent me down the rabbit-hole. I edited the original thing to include only the offending code and the solution. Thanks! :)
AmITheRWord
Yes, that would do it. :) Resource ID values in R are autogenerated ints. It looks like the IDs you were using translate to a shade of gray when interpreted as a packed ARGB value.
adamp