Search code examples
android-cursoradapterandroid-databinding

Android use Data Binding Library with CursorAdapter


I want to use the Android Data Binding Library with a ListView populated by a custom CursorAdapter, but I can't figure out how to get it work. I seems such a simple thing to achieve.

This is what I have now:

public class PlayCursorAdapter extends CursorAdapter {
    private List<Play> mPlays;

    PlayCursorAdapter(Context context, Cursor cursor) {
        super(context, cursor, 0);
        mPlays = new ArrayList<>();
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        ListItemPlayBinding binding = ListItemPlayBinding.inflate(LayoutInflater.from(context), parent, false);
        Play play = new Play();
        binding.setPlay(play);
        mPlays.add(play);
        return binding.getRoot();
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        int timeIndex = cursor.getColumnIndexOrThrow(PlayEntry.COLUMN_TIME);
        ...

        long time = cursor.getLong(timeIndex);
        ...

        Play play = mPlays.get(cursor.getPosition());

        play.setTime(time);
        ...
    }
}

Current behaviour:
When I run this code and I scroll down in the list I get a IndexOutOfBoundsException on the mPlays list.

Desired behaviour:
I want to populate a ListView with data from a ContentProvider using the Data Binding Library and a CursorAdapter. Is it even possible to use the Data Binding Library with a CursorAdapter? Or do you recommend to always use a RecyclerView and a RecyclerView.Adapter?


Solution

  • You should be able to avoid the problem by eliminating the mPlays list:

    public class PlayCursorAdapter extends CursorAdapter {
        PlayCursorAdapter(Context context, Cursor cursor) {
            super(context, cursor, 0);
        }
    
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            ListItemPlayBinding binding = ListItemPlayBinding.inflate(LayoutInflater.from(context), parent, false);
            Play play = new Play();
            binding.setPlay(play);
            return binding.getRoot();
        }
    
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            int timeIndex = cursor.getColumnIndexOrThrow(PlayEntry.COLUMN_TIME);
            ...
    
            long time = cursor.getLong(timeIndex);
            ...
            ListItemPlayBinding binding = DataBindingUtil.getBinding(view);
            Play play = binding.getPlay();
    
            play.setTime(time);
            ...
        }
    }
    

    This assumes you don't just want to instantiate a new Play each time you bindView().