RecyclerView and Databinding

The new DataBinding api is pretty easy to use for most simple bindings. When binding to a view that lives in a RecyclerView or other Adapter dependent View you need to stop and think a bit to get it right. We will walk through one way of getting this binding to work, and try to explain the idea behind it as we go along.
As usual we will create a Adapter and put that in our RecyclerView:

public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    // Initialize recycler view
    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    mAdapter = new MyAdapter(Data.list);
    mRecyclerView.setAdapter(mAdapter);
}
...

The adapter will create one CustomViewHolder for every position in the list of items that the adapter will display.

public class MyAdapter extends RecyclerView.Adapter {
    ...
    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        ViewDataBinding viewDataBinding = DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.my_text_layout, viewGroup, false);
        return new CustomViewHolder(viewDataBinding);
    }

    @Override
    public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
        ViewDataBinding viewDataBinding = customViewHolder.getViewDataBinding();
        viewDataBinding.setVariable(se.jayway.databinding.BR.mymodel, mMyModels.get(i));
    }
    ...

The only responsibility of the CustomViewHolder is to hold a reference to the ViewDataBinding for the ViewGroup it is associated with. Without DataBindings we would keep track of all the views in the incoming ViewGroup in the ViewHolder. This is not needed since the ViewDataBinding object will do this. Instead we create the ViewDataBinding object in onCreate and then keep it for use in the onBindViewHolder method calls.

public class MyModel extends BaseObservable {
    @Bindable
    private String data;

    public MyModel(String data) {
        setData(data);
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
        notifyPropertyChanged(se.jayway.databinding.BR.data);
    }
}

The MyModel object extends BaseObservable and this is how the actual binding is done, just like if the binding was done outside a adapter. So the trick for binding in data to views that are created and lives inside a adapter is just to keep track of the ViewDataBinding object rather than the view and then let the binding work its magic. More specifically line 12 in MyAdapter is the key to understanding the simplicity of this.

So all in all its not too difficult to tie in data in a adapter.

A full example can be found on github, thanx to Simon Zetterwall for puttning it together.

This Post Has 10 Comments

  1. Thanks a lot for this, I was struggling a lot to populate my views within the RecyclerView. Cheers!

  2. daniel

    what about a onclick event for RecyclerView item? set a Handler for ViewDataBinding? I do not have a good idea.

  3. Landon Chai

    Where are the following declared? Can’t seem to find them
    se.jayway.databinding.BR.mymodel
    se.jayway.databinding.BR.data

    1. Carl-Emil Kjellstrand

      se.jayway.databinding.BR.mymodel
      se.jayway.databinding.BR.data
      are generated classes. (Generated by the databindings library).

      Br Carl-Emil

  4. Gabriel

    Why would you use findviewbyid if you’re using databinding?

    1. Carl-Emil Kjellstrand

      Not sure how to call setLayoutManager via data-bindings. Got a good idea of how to improve this? If so please post it here for others to learn from!

      1. Gabriel

        You can use a BindingAdapter in your xml and than implement it (set over there the layoutmanager, animations maybe, adapter..etc)
        Example:

        and in your class do this:

        @BindingAdapter(“app:configuration”)
        public static void configureRecyclerView(RecyclerView recyclerView, RecyclerViewConfiguration configuration) {
        recyclerView.setLayoutManager(configuration.getLayoutManager());
        recyclerView.setItemAnimator(configuration.getItemAnimator());
        recyclerView.setAdapter(configuration.getAdapter());
        }

        PS. “app:configuration” it’s something custom, it could be app:anything, just make sure u respect the name in BindingAdapter.

        For more info, google custom BindingAdapter.
        One good article:
        https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47#.70ginb4qn

        From my point of view, if you use databinding you should have no logic in the View and definitely no findviewbyid, anywhere.

        Cheers :)

  5. Gabriel

    looks like the xml part that i posted got erased by the comment section, maybe you can do something about it:)

    1. Carl-Emil Kjellstrand

      I don’t think the blog allows xml unless you escape most of the chars, like < and > and / for example. And by the way, I really do like the suggestions you made! Looks much cleaner that way!

  6. Jacek

    Hi, very useful tutorial but any idea why my RecyclerView is displaying only the first item (out of 20 that are inside the list)? In which part of your code should I like for the problem? I am getting my data from an external API if that changes anything. Thank you.

Leave a Reply