更新:解决了一个问题:现在updateList
已解决,问题是我将mAdapter
定义为RecyclerView.Adapter
而不是{{1 }}。但是现在即使我正在获取数据,列表上也没有任何显示,它是空的
-------------------- 原始帖子 ------------------ -
我想使用MyAdapter
更新我的RecyclerView
以防止重复。
我有4个类:User类,设置数据的DiffUtil
类,Activity
类和Adapter
类。我不确定我是否能正确组合所有这四个。
这是User类:
DiffUtil
这是我动态设置数据的方式(我不断从包含要显示用户ID的服务器上获取新的public class User {
private String mUserId;
private Uri mImageUrl;
public User(String userId, String imageUrl) {
mUserId = userId;
mImageUrl = Uri.parse(imageUrl);
}
public String getUserId() {
return mUserId;
}
public Uri getImageUrl() {
return mImageUrl;
}
}
数组,然后从Json
存储中设置用户图像):(这是一个功能由onClick侦听器调用:)
这是片段中的方法调用:
Firebase
这是功能:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
updateUsersList();
}
});
这是我的 private void updateUsersList() {
@Override
public void onResponse(JSONArray response) { // the JSON ARRAY response of user ids ["uid1", "uid334", "uid1123"]
myDataset.clear(); // clear dataset to prevent duplicates
for (int i = 0; i < response.length(); i++) {
try {
String userKey = response.get(i).toString(); // the currently iterated user id
final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userKeyRef = rootRef.child("users").child(userKey); // reference to currently iterated user
ValueEventListener listener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
myDataset.add(new User(dataSnapshot.getKey(), dataSnapshot.child("imageUrl").getValue().toString())); //add new user: id and image url
mAdapter.updateList(myDataset); // cannot resolve this method, why?
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage());
}
};
userKeyRef.addListenerForSingleValueEvent(listener);
}
catch (JSONException e) { Log.d(TAG, "message " + e); }
}
}
类的样子:
DiffUtil
这是我的适配器:
public class MyDiffUtilCallBack extends DiffUtil.Callback{
ArrayList<User> oldUsers;
ArrayList<User> newUsers;
public MyDiffUtilCallBack(ArrayList<User> newUsers, ArrayList<User> oldUsers) {
this.newUsers = newUsers;
this.oldUsers = oldUsers;
}
@Override
public int getOldListSize() {
return oldUsers.size();
}
@Override
public int getNewListSize() {
return newUsers.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldUsers.get(oldItemPosition).getUserId().equals( newUsers.get(newItemPosition).getUserId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldUsers.get(oldItemPosition).equals(newUsers.get(newItemPosition));
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
//you can return particular field for changed item.
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
我不确定我是否正确组合了所有类(我第一次使用public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private ArrayList<User> mDataset;
private MyViewHolder myHolder;
private User user;
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView singleItemTextView;
public ImageView singleItemImage;
public View layout;
public ConstraintLayout constraintLayout;
public MyViewHolder(View v) {
super(v);
layout = v;
singleItemImage = (ImageView) v.findViewById(R.id.icon);
singleItemTextView = (TextView) v.findViewById(R.id.singleitemtv);
constraintLayout = (ConstraintLayout) v.findViewById(R.id.nbConstraintLayout);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<User> myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.nb_image_view, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
myHolder = holder;
user = mDataset.get(position);
Uri userImage = user.getImageUrl();
myHolder.singleItemTextView.setText(user.getUserId());
Glide.with(myHolder.itemView.getContext() /* context */)
.load(userImage)
.into(myHolder.singleItemImage);
myHolder.constraintLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(v.getContext(), DisplayUserActivity.class);
context.startActivity(intent);
}
});
}
public void updateList(ArrayList<User> newList) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffUtilCallBack(this.mDataset, newList));
diffResult.dispatchUpdatesTo(this);
}
}
),我也得到了DiffUtil
我在做什么错?
这是我在Fragment中定义mAdapter的方式:
cannot resolve method updateList(?)
答案 0 :(得分:6)
问题来自mAdapter
的定义。您将其定义为RecyclerView.Adapter
的超类MyAdapter
,并且其中不包含updateList()
。您应该将其更改如下:
private MyAdapter mAdapter;
更新1/13/2019:
我用AsyncListDiffer
重写了您的适配器,该适配器异步计算了差异,然后将其应用于适配器。
MyAdapter.java
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.constraint.ConstraintLayout;
import android.support.v7.recyclerview.extensions.AsyncListDiffer;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private AsyncListDiffer<User> mAsyncListDiffer;
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView singleItemTextView;
public ImageView singleItemImage;
public View layout;
public ConstraintLayout constraintLayout;
public MyViewHolder(View v) {
super(v);
layout = v;
singleItemImage = (ImageView) v.findViewById(R.id.icon);
singleItemTextView = (TextView) v.findViewById(R.id.singleitemtv);
constraintLayout = (ConstraintLayout) v.findViewById(R.id.nbConstraintLayout);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter() {
DiffUtil.ItemCallback<User> diffUtilCallback = new DiffUtil.ItemCallback<User>() {
@Override
public boolean areItemsTheSame(@NonNull User newUser, @NonNull User oldUser) {
return newUser.getUserId().equals(oldUser.getUserId());
}
@Override
public boolean areContentsTheSame(@NonNull User newUser, @NonNull User oldUser) {
return newUser.equals(oldUser);
}
};
mAsyncListDiffer = new AsyncListDiffer<>(this, diffUtilCallback);
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.nb_image_view, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
User user = mAsyncListDiffer.getCurrentList().get(position);
Uri userImage = user.getImageUrl();
holder.singleItemTextView.setText(user.getUserId());
Glide.with(holder.itemView.getContext() /* context */)
.load(userImage)
.into(holder.singleItemImage);
holder.constraintLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(v.getContext(), DisplayUserActivity.class);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mAsyncListDiffer.getCurrentList().size();
}
public void updateList(List<User> newList) {
mAsyncListDiffer.submitList(newList);
}
}
User.java
public class User {
private String mUserId;
private Uri mImageUrl;
public User(String userId, String imageUrl) {
mUserId = userId;
mImageUrl = Uri.parse(imageUrl);
}
public String getUserId() {
return mUserId;
}
public Uri getImageUrl() {
return mImageUrl;
}
@Override
public boolean equals(Object other) {
if (other instanceof User) {
User user = (User) other;
return mUserId.equals(user.getUserId()) && mImageUrl.equals(user.getImageUrl());
} else {
return false;
}
}
}
答案 1 :(得分:1)
除了@aminography的答案,我建议您使用ListAdapter
,这是一种RecyclerView.Adapter
的实现,可以更轻松地用正确的动画更新RecyclerView
。此类包含在recyclerview支持库中。
以下是根据您的用例使用的示例:
public class MyAdapter extends ListAdapter<User, UserViewHolder> {
public MyAdapter() {
super(new UserDiffCallback());
}
public UserViewHolder onCreateViewHolder(int position, int viewType) { ... }
public void onBindViewHolder(UserViewModel holder, int position) {
User userAtPosition = getItem(position); // getItem is a protected method from ListAdapter
// Bind user data to your holder...
}
}
public class UserDiffCallback extends DiffUtil.ItemCallback<User> {
@Override
public boolean areItemsTheSame(@NonNull User oldUser, @NonNull User newUser) {
return oldUser.getUserId().equals(newUser.getUserId());
}
@Override
public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) {
// No need to check the equality for all User fields ; just check the equality for fields that change the display of your item.
// In your case, both impact the display.
return oldUser.getUserId().equals(newUser.getUserId())
&& (oldUser.getImageUrl() == null) ? newUser.getImageUrl() == null : oldUser.getImageUrl().equals(newUser.getImageUrl());
}
}
然后,当您需要使用新用户更新列表时,请致电myAdapter.submitList(newList)
。就像AsyncListDiffer
一样,两个列表之间的差异是在后台线程上计算的。
答案 2 :(得分:0)
看起来像
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads)
未实施
实施此操作以正确使用DiffUtils,因为将对此更改进行调用,并且基于有效负载,您可以更新recyclerview项,而不用调用notifyDataSetChanged()
答案 3 :(得分:0)
修改您的方法:
public void updateList(ArrayList<User> newList) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffUtilCallBack(this.mDataset, newList));
this.mDataSet.clear()
this.mDataSet.addAll(newList)
diffResult.dispatchUpdatesTo(this);
}