weirdo16 weirdo16 - 3 months ago 32
Android Question

Android ArrayAdapter not properly converting Views

I have a custom

ArrayAdapter
for a
ListView
that uses a custom row layout, defined separately in XML. The layout is just three
TextViews
and an
ImageView
, put together in a
RelativeLayout
. To improve performance, the adapter uses a ViewHolder system like the one described here to convert existing Views instead of inflating new ones. In
ArrayAdapter.getView()
, the adapter is supposed to bold or unbold the first TextView, depending on a boolean.

When I first open the app, all of the TextViews are properly bolded or unbolded. However, if I scroll to the bottom of the ListView, then scroll back to the top, all of the title TextViews are bold, even if they aren't supposed to be. I think it must have something to do with converting existing views that are already bold, but I can't figure out what it is. I've debugged the app with Android Studio, and it runs just like I think it should -- when I scroll back up, the adapter properly bolds/unbolds things in the debug window, but they all seem to be bold on the app.

One thing I have noticed is that if I change the
textStyle
attribute of the TextView to "bold," all the title TextViews are bold from the beginning, and never change. It's only if I remove
textStyle
or set it to "normal" that the TextViews are normal at the start.

Here's getView() in the ArrayAdapter:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
PostShell shell = postShellList.get(getCount() - 1 - position); //I stack my ListView backwards, so index 0 is at the bottom
ViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_layout, parent, false);
holder = new ViewHolder();
holder.firstLine = (TextView) convertView.findViewById(R.id.firstLine);
holder.secondLine = (TextView) convertView.findViewById(R.id.secondLine);
holder.thirdLine = (TextView) convertView.findViewById(R.id.thirdLine);
holder.image = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.firstLine.setText(shell.postTitle);
if (shell.unread) {
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.BOLD);
} else {
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.NORMAL);
}
//convert other TextViews
}


My ViewHolder class is just a static class with a few TextViews and an ImageView.

And here's the relevant part of the code for the row layout I'm using:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="88dp">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="84dp"
android:paddingRight="16dp"
android:paddingTop="6dp"
android:id="@+id/firstLine"
android:ellipsize="end"
android:text="First"
android:textStyle="normal"
android:singleLine="true" />

<!-- other views -->

</RelativeLayout>

Answer

The problem seems to be that "unboldening" the text does not work with the following statement:

holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.NORMAL);

The following snippet leaves out the holder.firstLine.getTypeface() and just uses a simpler variety of setTypeface(). Worked for me.

if (shell.unread) {
    holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.BOLD);
} else {
    holder.firstLine.setTypeface(Typeface.DEFAULT);
}