[英]RecyclerView.Adapter notifyDataSetChanged() not working when is showing last item
[英]RecyclerView with RecyclerView.Adapter not updating when more than 1 item
我有一个带有 RecyclerView 适配器的 RecyclerView ,它只会在只有 1 个孩子时才更新,而当有 2 个或更多孩子不更新信息时。 要显示正确的信息,我需要关闭然后重新打开应用程序。
用调试器检查,发现更新数据时正确完整的信息确实到达了onBindViewHolder方法,但即使我调用notifyDataSetChanged也不更新UI,这里是代码:
这是适配器和 recyclerview 初始化的时候:
LinearLayoutManager layoutManagerForServers = new LinearLayoutManager(getContext());
recyclerViewServers.setLayoutManager(layoutManagerForServers);
mainArrayListForServers = new ArrayList<>();
mAdapterForServers = new ViewServersAdapter(getContext());
recyclerViewServers.setAdapter(mAdapterForServers);
这是数据更新的时间:
final ViewModelForServers viewModel = new ViewModelProvider(this).get(ViewModelForServers.class);
final LiveData<ArrayList<Server>> liveData = viewModel.getServersMediatorLiveData();
liveData.observe(this, new Observer<ArrayList<Server>>() {
@Override
public void onChanged(@Nullable ArrayList<Server> serverArrayList) {
if (serverArrayList != null) {
mainArrayListForServers = serverArrayList;
// update the UI here with values in the snapshot
mAdapterForServers.setServersArrayList(mainArrayListForServers);
mAdapterForServers.notifyDataSetChanged();
setEmptyView();
}
}
});
最后这是回收器适配器:
public class ViewServersAdapter extends RecyclerView.Adapter<ViewServersAdapter.MyViewHolder> {
private ArrayList<Server> serversArrayList = new ArrayList<>();
private ViewServersFragmentItemBinding viewServersFragmentItemBinding;
private Context context;
ViewServersAdapter(Context context){
this.context = context;
}
static class MyViewHolder extends RecyclerView.ViewHolder{
Context context;
MyViewHolder(@NonNull View itemView, Context context) {
super(itemView);
this.context = context;
}
void bindView(Server server, ViewServersFragmentItemBinding viewQFragmentItemBinding){
TextView serverNameTxt = viewQFragmentItemBinding.serverName;
TextView serverStatus = viewQFragmentItemBinding.serverStatus;
TextView serverNumber = viewQFragmentItemBinding.serverNumber;
TextView userOnCall = viewQFragmentItemBinding.userOnCall;
TextView duration = viewQFragmentItemBinding.callDuration;
ImageView userProfile = viewQFragmentItemBinding.profilePicture;
serverNameTxt.setText(server.getServerName());
serverStatus.setText(Utils.getServerStatus(server.getServerStatus(),context));
serverNumber.setText(String.valueOf(server.getServerNumber()).substring(3));
if (server.getCallRequest()!= null){
userOnCall.setText(server.getCallRequest().getUser());
duration.setText(Utils.getTimeOnMinutes(server.getCallRequest().getTime(),context,false));
Uri profilePictureUri = Uri.parse(server.getCallRequest().getProfilePicture());
userProfile.setScaleX(1);
userProfile.setImageResource(ListOfProfilePictureSmallsInt.get(Utils.getPhotoUrlIndex(profilePictureUri)));
} else {
userOnCall.setText("");
duration.setText("");
userProfile.setScaleX(-1);
userProfile.setImageResource(R.drawable.ic_waiting);
}
}
}
void setServersArrayList(ArrayList<Server> serverArrayList){
this.serversArrayList = serverArrayList;
}
@NonNull
@Override
public ViewServersAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
viewServersFragmentItemBinding = ViewServersFragmentItemBinding.inflate(inflater,parent,false);
// create a new view
ConstraintLayout v = (ConstraintLayout) viewServersFragmentItemBinding.getRoot();
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, //width
ViewGroup.LayoutParams.WRAP_CONTENT);//height
v.setLayoutParams(lp);//override default layout params
return new MyViewHolder(v, context);
}
@Override
public void onBindViewHolder(@NonNull ViewServersAdapter.MyViewHolder holder, int position) {
Server server = serversArrayList.get(position);
holder.bindView(server, viewServersFragmentItemBinding);
}
@Override
public int getItemCount() {
return serversArrayList.size();
}
}
我真的很感激任何帮助。 谢谢
它是嵌套RecyclerView
在另一个RecyclerView
? 配置更改(屏幕旋转)后是否更新?
我多次遇到相同的错误,尽管所有适配器操作都已完成,但当添加新元素时,recyclerview 不会更新 UI。 我在这里使用了一种解决方法: mRecyclerView.scrollBy(0,1)
,尝试在notifyDataSetChanged()
调用后notifyDataSetChanged()
调用它。
RecyclerView
实际行为如何? 它是否显示所有项目? 它们是否都更新了相同的信息? 或者它只是更新的最后一个项目?
编辑
问题似乎不是 RV 没有更新 UI,而是数据绑定以及您如何使用它。 它实际上只是正确更新的最后一项吗?
问题是您的viewServersFragmentItemBinding
在您的适配器类中声明,但它应该声明并保存在 viewholder 类中(也是最终的)。 这意味着在调用所有onCreateViewHolder
方法后,仅存储最后一个 viewholder 的数据绑定,并且所有以下onBindViewHolder
方法调用bindView
将引用传递给最后一个viewholder
的绑定。
RecyclerView
回收视图持有者,这意味着它不会在数据更改时重新创建它们,并且视图仅在第一次调用时创建 - 这就是为什么它在您重新打开应用程序或旋转屏幕时工作 - onCreateViewHolder
和onBindViewHolder
被onBindViewHolder
调用记录在您的列表中,正确绑定视图。
然后,当数据更改并且您调用onDataSetChanged()
,永远不会调用onCreateViewHolder
方法,因为您已经拥有所有ViewHolder
,只有onBindViewHolder
方法会被调用。 问题是他们使用对最后一项数据绑定的相同引用调用bindView
。
检查文章https://medium.com/androiddevelopers/android-data-binding-recyclerview-db7c40d9f0e4
数据绑定是在onCreateViewHolder
创建的
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, viewType, parent, false);
return new MyViewHolder(binding);
}
public void onBindViewHolder(MyViewHolder holder, int position) {
Object obj = getObjForPosition(position);
holder.bind(obj);
}
但仅在ViewHolder
存储和访问
public class MyViewHolder extends RecyclerView.ViewHolder {
private final ViewDataBinding binding;
public MyViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object obj) {
binding.setVariable(BR.obj, obj);
binding.executePendingBindings();
}
}
您可以做一件事,在适配器类中添加一个方法,如下所示
public void updateData(ArrayList<Server> serversArrayList)
{
this.serversArrayList = serversArrayList;
notifyDataSetChanged();
}
然后像这样从活动和视图模型中调用它
mAdapterForServers.updateData(serverArrayList);
首先,您需要使用空列表初始化 recyclerview 适配器
LinearLayoutManager layoutManagerForServers = new LinearLayoutManager(getContext());
recyclerViewServers.setLayoutManager(layoutManagerForServers);
mainArrayListForServers = new ArrayList<>();
mAdapterForServers = new ViewServersAdapter(getContext(),mainArrayListForServers);
recyclerViewServers.setAdapter(mAdapterForServers);
您的适配器应将 arraylist 作为构造函数中的参数
public class ViewServersAdapter extends RecyclerView.Adapter<ViewServersAdapter.MyViewHolder> {
private ArrayList<Server> serversArrayList;
private ViewServersFragmentItemBinding viewServersFragmentItemBinding;
private Context context;
ViewServersAdapter(Context context,ArrayList<Server> serversArrayList){
this.context = context;
this.serversArrayList = serversArrayList;
}
static class MyViewHolder extends RecyclerView.ViewHolder{
Context context;
MyViewHolder(@NonNull View itemView, Context context) {
super(itemView);
this.context = context;
}
void bindView(Server server, ViewServersFragmentItemBinding viewQFragmentItemBinding){
TextView serverNameTxt = viewQFragmentItemBinding.serverName;
TextView serverStatus = viewQFragmentItemBinding.serverStatus;
TextView serverNumber = viewQFragmentItemBinding.serverNumber;
TextView userOnCall = viewQFragmentItemBinding.userOnCall;
TextView duration = viewQFragmentItemBinding.callDuration;
ImageView userProfile = viewQFragmentItemBinding.profilePicture;
serverNameTxt.setText(server.getServerName());
serverStatus.setText(Utils.getServerStatus(server.getServerStatus(),context));
serverNumber.setText(String.valueOf(server.getServerNumber()).substring(3));
if (server.getCallRequest()!= null){
userOnCall.setText(server.getCallRequest().getUser());
duration.setText(Utils.getTimeOnMinutes(server.getCallRequest().getTime(),context,false));
Uri profilePictureUri = Uri.parse(server.getCallRequest().getProfilePicture());
userProfile.setScaleX(1);
userProfile.setImageResource(ListOfProfilePictureSmallsInt.get(Utils.getPhotoUrlIndex(profilePictureUri)));
} else {
userOnCall.setText("");
duration.setText("");
userProfile.setScaleX(-1);
userProfile.setImageResource(R.drawable.ic_waiting);
}
}
}
@NonNull
@Override
public ViewServersAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
viewServersFragmentItemBinding = ViewServersFragmentItemBinding.inflate(inflater,parent,false);
// create a new view
ConstraintLayout v = (ConstraintLayout) viewServersFragmentItemBinding.getRoot();
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, //width
ViewGroup.LayoutParams.WRAP_CONTENT);//height
v.setLayoutParams(lp);//override default layout params
return new MyViewHolder(v, context);
}
@Override
public void onBindViewHolder(@NonNull ViewServersAdapter.MyViewHolder holder, int position) {
Server server = serversArrayList.get(position);
holder.bindView(server, viewServersFragmentItemBinding);
}
@Override
public int getItemCount() {
return serversArrayList.size();
}
}
那么你应该像这样更新arraylist:
final ViewModelForServers viewModel = new ViewModelProvider(this).get(ViewModelForServers.class);
final LiveData<ArrayList<Server>> liveData = viewModel.getServersMediatorLiveData();
liveData.observe(this, new Observer<ArrayList<Server>>() {
@Override
public void onChanged(@Nullable ArrayList<Server> serverArrayList) {
if (serverArrayList != null) {
mainArrayListForServers.clear();
mainArrayListForServers.addAll(serverArrayList);
mAdapterForServers.notifyDataSetChanged();
}
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.