繁体   English   中英

当超过 1 个项目时,带有 RecyclerView.Adapter 的 RecyclerView 不更新

[英]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回收视图持有者,这意味着它不会在数据更改时重新创建它们,并且视图仅在第一次调用时创建 - 这就是为什么它在您重新打开应用程序或旋转屏幕时工作 - onCreateViewHolderonBindViewHolderonBindViewHolder调用记录在您的列表中,正确绑定视图。

然后,当数据更改并且您调用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM