How can I use Android DataBinding in a listview and still use a ViewHolder pattern?

Brett picture Brett · Nov 11, 2016 · Viewed 7.7k times · Source

I have an Android activity that pulls its data from an observable list inside an adapter class.

My getView() method in my adapter class is:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (inflater == null) {
        inflater = (LayoutInflater) parent.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    // Perform the binding
    ActivityTeamMessageListRowBinding binding = DataBindingUtil.inflate(inflater, R.layout.my_activity_list_row, parent, false);
    binding.setInfo(list.get(position));
    binding.executePendingBindings();

    // Return the bound view
    return binding.getRoot();
}

And this works great. However, I see the Android-warning unconditional layout inflation from view adapter on the ActivityTeamMessageListRowBinding binding ... line.

I have been researching ViewHolders to fix this issue, but I can't seem to figure out how to accomplish this and still use my data binding. And presumably, the longer the list, the worse performance I'd see without using a ViewHolder.

Does anyone know how to extend my getView(...) code to incorporate a view binder? I have a 3 TextViews and 1 ImageView in my my_activity_list_row.xml.

Answer

CommonsWare picture CommonsWare · Nov 11, 2016

Try this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (inflater == null) {
        inflater = ((Activity) parent.getContext()).getLayoutInflater();
    }

    // Perform the binding

    ActivityTeamMessageListRowBinding binding = DataBindingUtil.getBinding(convertView);

    if (binding == null) {
        binding = DataBindingUtil.inflate(inflater, R.layout.my_activity_list_row, parent, false);
    }

    binding.setInfo(list.get(position));
    binding.executePendingBindings();

    // Return the bound view
    return binding.getRoot();
}

I haven't used data binding with ListView (I'll use RecyclerView), but off the cuff, this is what I'd try. Use breakpoints or logging to confirm that, when convertView is not null, that you get binding back from getBinding() more often than not (and perhaps all the time — I'm hazy on how data binding's caching works).