16

I'm trying to use Android's Data Binding features with a custom adapter and a ListView. I'm having trouble overriding the custom adapter's getView method:

public class ChecksAdapter extends ArrayAdapter<Check> {

    public ChecksAdapter(Context context, ObservableList<Check> checks) {
        super(context, R.layout.check, checks);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        CheckBinding binding = DataBindingUtil.inflate(
                LayoutInflater.from(getContext()),
                R.layout.check, parent, false);
        binding.setCheck(this.getItem(position));

        // Return what?
    }
    
}

So my questions are:

  • Where do I get the View element that I should be returning? Or in other words, how can I bind the object to an inflated/converted view?
  • How can I reuse convertView when using data binding?
  • Is this the correct way to implement this? The guide is not very clear on ListViews

Here's the only reference of ListViews in the guide:

If you are using data binding items inside a ListView or RecyclerView adapter, you may prefer to use:

   ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
   //or
   ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

7 Answers 7

28

You should do the following for smooth scrolling though..

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    CheckBinding binding;
    if(convertView == null) {
        binding = DataBindingUtil.inflate(
                LayoutInflater.from(getContext()),
                R.layout.check, parent, false);
        convertView = binding.getRoot();
    }
    else {
        binding = (CheckBinding) convertView.getTag();
    }

    binding.setCheck(this.getItem(position));
    convertView.setTag(binding);
    return convertView;
}
Sign up to request clarification or add additional context in comments.

3 Comments

i don't know why but this is not working for me when i am using a cursor adapter
@sergi why are you checking if the convertView is null?
@Thalatta the first time that row is displayed the convertView.getTag() will return a null object because it has never been initialized. The code in the if branch will only be executed as initialization the first time the visible rows are displayed. As you scroll, the else branch will be reached.
11

According to this, you should return binding.getRoot().

View getRoot ()

Returns the outermost View in the layout file associated with the Binding. If this binding is for a merge layout file, this will return the first root in the merge tag.

Comments

5

For completes here is the kotlin variant:

    val binding = convertView?.tag as? CheckBinding ?: CheckBinding.inflate(layoutInflater, parent, false)
    binding.check = this.getItem(position)
    binding.root.tag = binding

    return binding.root

Comments

2

Recommended way

Use generated Binding class instead of DataBindingUtil class. See Documentation.

If you are using data binding items inside a Fragment, ListView, or RecyclerView adapter, you may prefer to use the inflate() methods of the bindings classes

Use

binding = CheckBinding.inflate(this, parent, false);

instead of

binding = DataBindingUtil.inflate(
                LayoutInflater.from(getContext()),
                R.layout.check, parent, false);

Other code will be same as @sergi

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    CheckBinding binding;
    if(convertView == null) {
        binding = CheckBinding.inflate(this, parent, false);
        convertView = binding.getRoot();
    }
    else {
        binding = (CheckBinding) convertView.getTag();
    }

    binding.setCheck(this.getItem(position));
    convertView.setTag(binding);
    return convertView;
}

1 Comment

When I use this approach, I often get lint warnings indicating R.layout.check appears to be unused. Hence, I prefer to use DataBindingUtil
1
ItemTickFilterBinding mFilterBinding;

    if (convertView==null) {
        mFilterBinding= DataBindingUtil.inflate(
                LayoutInflater.from(mContext),
                R.layout.item_tick_filter, parent, false);
        convertView.setTag(mFilterBinding);
    }
    else {
        mFilterBinding=(ItemTickFilterBinding)convertView.getTag();
    }

1 Comment

in base adapter's method getView .mFilterBinding is the instance of listrow layout and u should set tag on convert view and get in else part also.
0

DataBindingUtil will save the ViewDataBinding object to view.tag, so you can retrieve it later by DataBindingUtil.getBinding(convertView)

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getViewForResource(mResourceId, position, convertView, parent);
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return getViewForResource(mDropDownResourceId, position, convertView, parent);
}

public View getViewForResource(int resourceId, int position, View convertView, ViewGroup parent) {
    final ViewDataBinding binding = (convertView != null) ? DataBindingUtil.getBinding(convertView) : DataBindingUtil.inflate(mLayoutInflater, resourceId, parent, false);
    binding.setVariable(BR.viewModel, getItem(position));
    return binding.getRoot();
}

Comments

-1

For GridView adapters or custom adapter following code worked for me :

override fun getView(position: Int, convertView: View?, container: ViewGroup?): View {
    val binding = convertView?.tag as? MenuItemBinding ?:
    MenuItemBinding.inflate(LayoutInflater.from(ctx), container, false)

    val menuItem = menuList[position]
    binding.txtVw.text = menuItem.title
    binding.imgVwIcon.setImageResource(menuItem.iconId)
    return binding.root
}

MenuItemBinding is on the basis of the name of the layout file here the layout file name is 'menu_item.xml'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.