如何以最优性能通过代码设置TextView的文字颜色?
Great question—since RecyclerView’s onBindViewHolder gets called constantly as users scroll, even tiny overhead adds up and can hurt scrolling smoothness. Let’s walk through targeted tweaks to your code to squeeze out better performance without sacrificing functionality.
1. Cache Color Values Upfront (Avoid Repeating Resource Lookups)
Your current setTextColor method calls ContextCompat.getColor() every time you set a TextView’s color. This method does resource resolution work, which is cheap on its own but adds up when called 5 times per item, multiplied by dozens of items during scrolling.
Instead, resolve your color resources once when initializing your Adapter, then reuse those precomputed integer values:
public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> { // Cache colors once instead of resolving them every time private final int colorRed; private final int colorBlue; private final int colorGreen; private List<YourModel> arrayListFiltered; public YourAdapter(Context context, List<YourModel> filteredData) { this.arrayListFiltered = filteredData; // Resolve colors once during Adapter initialization colorRed = ContextCompat.getColor(context, R.color.red); colorBlue = ContextCompat.getColor(context, R.color.blue); colorGreen = ContextCompat.getColor(context, R.color.green); } // ... rest of your Adapter code ... @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { YourModel item = arrayListFiltered.get(position); int textColor = colorGreen; // Default to green String type = item.getType(); if (!FormatFactory.isStringEmpty(type)) { String lowerType = type.toLowerCase(); if (lowerType.contains("featured")) { textColor = colorRed; } else if (lowerType.contains("connector")) { textColor = colorBlue; } } // Use cached color values directly holder.tv_rating_type.setTextColor(textColor); holder.tv_length.setTextColor(textColor); holder.tv_name.setTextColor(textColor); holder.tv_location.setTextColor(textColor); holder.tv_summary.setTextColor(textColor); } // ... ViewHolder class ... }
2. Batch TextView Updates (Cleaner Code, Minor Performance Win)
To avoid repeating setTextColor five times, you can store your TextViews in a list inside the ViewHolder and loop through them. This reduces code duplication and minimizes redundant method call overhead:
static class ViewHolder extends RecyclerView.ViewHolder { TextView tv_rating_type; TextView tv_length; TextView tv_name; TextView tv_location; TextView tv_summary; List<TextView> colorableTextViews; // List for batch updates ViewHolder(View itemView) { super(itemView); // Initialize individual TextViews tv_rating_type = itemView.findViewById(R.id.tv_rating_type); tv_length = itemView.findViewById(R.id.tv_length); tv_name = itemView.findViewById(R.id.tv_name); tv_location = itemView.findViewById(R.id.tv_location); tv_summary = itemView.findViewById(R.id.tv_summary); // Populate the batch list colorableTextViews = Arrays.asList( tv_rating_type, tv_length, tv_name, tv_location, tv_summary ); } }
Then in onBindViewHolder, replace the five lines with a loop:
for (TextView tv : holder.colorableTextViews) { tv.setTextColor(textColor); }
3. Move String Processing to Data Preparation (Reduce onBind Work)
Right now, you’re calling toLowerCase() and contains() on the type string every time onBindViewHolder runs. These string operations are cheap, but they’re unnecessary to repeat for every scroll. Instead, precompute the color for each item once when you filter or load your data:
Option 1: Add a color field to your data model
public class YourModel { private String type; private int textColor; // Precomputed color value // Set this color when you first load/filter the item public void setTextColor(int color) { this.textColor = color; } public int getTextColor() { return textColor; } }
Option 2: Preprocess your filtered list
When you create arrayListFiltered, compute the color for each item then and there:
// When filtering your data (do this once, not in onBind) public List<YourModel> prepareFilteredData(List<YourModel> rawData, Context context) { List<YourModel> filtered = new ArrayList<>(); int red = ContextCompat.getColor(context, R.color.red); int blue = ContextCompat.getColor(context, R.color.blue); int green = ContextCompat.getColor(context, R.color.green); for (YourModel item : rawData) { // Apply your filtering logic here... // Compute color once per item int itemColor = green; String type = item.getType(); if (!FormatFactory.isStringEmpty(type)) { String lowerType = type.toLowerCase(); if (lowerType.contains("featured")) { itemColor = red; } else if (lowerType.contains("connector")) { itemColor = blue; } } item.setTextColor(itemColor); filtered.add(item); } return filtered; }
Now onBindViewHolder becomes super lightweight:
@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { YourModel item = arrayListFiltered.get(position); int textColor = item.getTextColor(); for (TextView tv : holder.colorableTextViews) { tv.setTextColor(textColor); } }
Why These Changes Matter
Each tweak addresses a small source of overhead, but together they reduce the work the UI thread has to do during scrolling:
- Caching colors avoids repeated resource resolution calls.
- Batch updates cut down on redundant method invocations.
- Preprocessing data moves string operations out of the high-frequency
onBindViewHoldermethod.
These changes won’t make a huge difference in small lists, but they’ll help maintain smooth scrolling when dealing with large datasets or fast scrolling.
内容的提问来源于stack exchange,提问作者seekingStillness

