6

I am using the ListAdapter in the Support library along with LiveData to observe my Room database (my implementation is similar to the one shown here). For some reason, my recycler view is not animating when the data is updated. The new items get added to the adapter however they remain outside the recycler view so I have to manually scroll up to view them. Why is this happening?

ItemAdapter.java

public class ItemRecyclerAdapter extends ListAdapter<Item, PostViewHolder> {
    public static final DiffUtil.ItemCallback<Item> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<Item>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull Item oldItem, @NonNull Item newItem) {
                    return Objects.equals(oldItem.id, newItem.id);
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull Item oldItem, @NonNull Item newItem) {
                    return Objects.equals(oldItem.content, newItem.content);
                }
            };

    public ItemRecyclerAdapter() {
        super(DIFF_CALLBACK);
    }

    @NonNull
    @Override
    public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new PostViewHolder(LayoutInflater.from(parent.getContext())
                .inflate(R.layout.post_item, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
        holder.onBind(getItem(position));
    }
}

In my fragment -

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
        adapter = new ItemRecyclerAdapter();
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));

        viewModel = ViewModelProviders.of...
        viewModel.setData(...);
        viewModel.getPosts().observe(this, listResource -> {
        if (listResource != null && listResource.data != null) {
            adapter.submitList(listResource.data);
        }
    });
}
jL4
  • 1,238
  • 10
  • 15
  • Did you ever find a solution for this? I'm having the same issue. – danielnovais92 Jun 04 '18 at 00:38
  • 1
    @danielnovais92 I haven't but I think this is the default behavior of DiffUtil(check [this](https://stackoverflow.com/a/47522246)). It does not scroll to the top if the new list contains an item present in the older list. So clearing the older data before setting the new data should do the trick but that defeats the purpose of DiffUtil. You can try [this](https://stackoverflow.com/a/43461324) but it's probably better to preserve the current position and notify the user about new items using a popup notification like [this](http://www.webianks.com/popupbubble/3.png) – jL4 Jun 06 '18 at 16:47

1 Answers1

2

like use below code user pojo class

    @Entity
public class User {
    public static DiffCallback<User> DIFF_CALLBACK = new DiffCallback<User>() {
        @Override
        public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            return oldItem.userId == newItem.userId;
        }

        @Override
        public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            return oldItem.equals(newItem);
        }
    };

    @SerializedName("id")
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "user_id")
    public long userId;

    @SerializedName("login")
    @ColumnInfo(name = "first_name")
    public String firstName;
    public String address;

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;

        User user = (User) obj;

        return user.userId == this.userId && user.firstName == this.firstName;
    }
}

then after adapter like below code..

public class UserAdapter extends ListAdapter<User, UserAdapter.UserItemViewHolder> {


public UserAdapter() {
    super(User.DIFF_CALLBACK);
}

@Override
public UserItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    View view = layoutInflater.inflate(R.layout.item_user_list, parent, false);
    return new UserItemViewHolder(view);
}

@Override
public void onBindViewHolder(UserItemViewHolder holder, int position) {
    User user= getItem(position);
    if(user!=null) {
        holder.bindTo(user);
    }
}

static class UserItemViewHolder extends RecyclerView.ViewHolder {
    TextView userName, userId;

    public UserItemViewHolder(View itemView) {
        super(itemView);
        userId = itemView.findViewById(R.id.userId);
        userName = itemView.findViewById(R.id.userName);
    }

    public void bindTo(User user) {
        userName.setText(user.firstName);
        userId.setText(String.valueOf(user.userId));
    }
}

}

and view model class like below ..

public class UserViewModel extends ViewModel {

public LiveData<PagedList<User>> userList;

public UserViewModel() {

}

public void init(UserDao userDao) {
   PagedList.Config pagedListConfig =
            (new PagedList.Config.Builder()).setEnablePlaceholders(true)
                    .setPrefetchDistance(10)
                    .setPageSize(20).build();

    userList = (new LivePagedListBuilder(userDao.usersByFirstName(), pagedListConfig))
            .build();
}

}

recycler view bind data like below code..

    private void initView() {
    RecyclerView recyclerView = findViewById(R.id.plRvData);
    LinearLayoutManager llm = new LinearLayoutManager(this);
    llm.setOrientation(LinearLayoutManager.VERTICAL);
    recyclerView.setLayoutManager(llm);
    userDao=demoDatabase.getUserDao();
    UserViewModel viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
    viewModel.init(userDao);
    final UserAdapter userUserAdapter = new UserAdapter();

    viewModel.userList.observe(this, pagedList -> {
        userUserAdapter.setList(pagedList);
    });
    Log.d("Vikas:::","Vikas PAndey");
    recyclerView.setAdapter(userUserAdapter);

}
  • I have a similar use case with a basic RecyclerView where I am trying to reload the entire RecyclerView list when the user presses back space: https://stackoverflow.com/questions/56766367/recyclerview-how-to-refresh-full-list-of-cardviews-with-viewmodel Any thoughts on how to fix? – AJW Jun 27 '19 at 18:19