henryblue / TvRecyclerView

A custom RecyclerView for Android TV end
Apache License 2.0
6 stars 4 forks source link

DiffUtil Focus Issues #21

Open kingargyle opened 5 years ago

kingargyle commented 5 years ago

When using DiffUtil to notify the recylcerView, there are display issues. In particular Focus gets stuck and doesn't know where to go after the animations are complete. Also a View will get stuck on the screen that was being animated off.

TvRecylcerVierw may need to implement the ItemAnimatorFinished, and set the selectedItem and focus to the appropriate spot.

Not sure if there is a way to know when ItemAnimations start so we can disable the focus selection. In particular it seems the item that is focused, is the one getting stuck. In general though, seems to get wonky with DiffUtil.

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ItemAnimator.ItemAnimatorFinishedListener

For now I'll just hold off on using diffUtil, but it would be nice to use this, and the Item Animators from here: https://github.com/wasabeef/recyclerview-animators

henryblue commented 5 years ago

You can try this problem with version 1.1.4

kingargyle commented 5 years ago

Thanks will try it tonight.

kingargyle commented 5 years ago

We are close, but if the focus is on the first item in the RecyclerView, and you change the content, I get a stuck image when the content changes (see picture below). If the focus is not on the first item, but any other item in the list, it works as expected now.

I can't navigate the list if the focus is stuck.

image

henryblue commented 5 years ago

I didn't test it out(include add/remove/update), my test case(test update):

public class DiffCallback extends DiffUtil.Callback {

private ArrayList<DataItem> mOldList;

private ArrayList<DataItem> mNewList;

public DiffCallback(ArrayList<DataItem> oldList, ArrayList<DataItem> newList) {
    mOldList = oldList;
    mNewList = newList;
}

@Override
public int getOldListSize() {
    return mOldList.size();
}

@Override
public int getNewListSize() {
    return mNewList.size();
}

@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    return mOldList.get(oldItemPosition).id.equals(mNewList.get(newItemPosition).id);
}

@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
    return mOldList.get(oldItemPosition).content.equals(mNewList.get(newItemPosition).content);
}

}

Initialize raw data and data that needs to be updated:

private void initData() {
    for (int i = 0; i < ContantUtil.TEST_DATAS.length; i++) {
        DataItem item = new DataItem();
        item.id = String.valueOf(i);
        item.content = ContantUtil.TEST_DATAS[i];
        mOldList.add(item);
        if (i % 2 == 0) {
            DataItem itemNew = new DataItem();
            itemNew.id = "X" + i;
            itemNew.content = "X" + ContantUtil.TEST_DATAS[i];
            mNewList.add(itemNew);
        } else {
            mNewList.add(item);
        }
    }
}

Simulate update data:

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_0) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(mOldList, mNewList));
        diffResult.dispatchUpdatesTo(mAdapter);
        mAdapter.setData(mNewList);
    }
    return super.onKeyDown(keyCode, event);
}
kingargyle commented 5 years ago
  1. Make sure that the recylcerview has the first item selected, by doing:

    tvRecyclerView.setItemSelected(0);
  2. Make sure in the new list, the first item is the same id in both result sets.

  3. Update the data and run the diffutil.

My setData looks like the following.

  setData(mNewList) {
      List oldList = new ArrayList(currentList);

      currentList.clear()
      currentList.addAll(newList);
      DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(oldList, currentList));
      diffResult.dispatchUpdatesTo(this);
  }

That is really the only difference from what you have and what I have, and I verified I am using 1.1.4.

It'll probably be a few days before I can do any more debugging.