Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recyclerview does not animate when using DiffUtil ListAdapter

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);
        }
    });
}
like image 514
jL4 Avatar asked Apr 11 '18 08:04

jL4


People also ask

When to use DiffUtil?

DiffUtils is used to track changes made to the RecyclerView Adapter. DiffUtil notifies the RecyclerView of any changes to the data set using the following methods: notifyItemMoved. notifyItemRangeChanged.

What is DiffUtil ItemCallback?

DiffUtil. Callback serves two roles - list indexing, and item diffing. ItemCallback handles just the second of these, which allows separation of code that indexes into an array or List from the presentation-layer and content specific diffing code.

How DiffUtil works in Android?

Understanding the DiffUtil Algorithm Myers difference algorithm. This calculates the difference between both sets of elements. Myers algorithm does not handle elements that are moved so DiffUtil runs a second pass on the result that detects which elements moved.

What is Diff util?

DiffUtil is a utility class that calculates the difference between two lists and outputs a list of update operations that converts the first list into the second one. It can be used to calculate updates for a RecyclerView Adapter.


1 Answers

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);

}
like image 133
Android Team Avatar answered Sep 27 '22 21:09

Android Team