RecyclerView с RecyclerView.Adapter не обновляется, когда более 1 элемента - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть RecyclerView с адаптером RecyclerView, который обновляется только так, как положено, когда есть только 1 ребенок, когда 2 или более не обновляет информацию. Чтобы получить правильную информацию, мне нужно закрыть, а затем снова открыть приложение.

Проверил с помощью отладчика и обнаружил, что правильная и полная информация достигает метода onBindViewHolder при обновлении данных, но не обновляет пользовательский интерфейс даже когда я вызываю notifyDataSetChanged, вот код:

Это когда инициализируется адаптер и просмотрщик:

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

}

Буду очень признателен за любую помощь. Спасибо

Ответы [ 3 ]

1 голос
/ 01 апреля 2020

Это вложенное RecyclerView в другом RecyclerView? Обновляется ли он после изменения конфигурации (поворот экрана)?

Я неоднократно встречался с одной и той же ошибкой, просмотр при повторном использовании не обновляет пользовательский интерфейс при добавлении новых элементов, хотя все действия адаптера выполнены. Я использую обходной путь здесь: mRecyclerView.scrollBy(0,1), попробуйте позвонить сразу после notifyDataSetChanged() вызова.

Как на самом деле ведет себя RecyclerView? Это показывает все предметы? Все ли они обновлены с одинаковой информацией? Или это только последний элемент, который обновляется?

Редактировать

Похоже, проблема не в том, что RV не обновляет пользовательский интерфейс, а в том, как привязка данных и как вы используете Это. Это только последний элемент, который обновляется правильно?

Проблема в том, что ваш viewServersFragmentItemBinding объявлен в вашем классе адаптера, но он должен быть объявлен и сохранен в классе видоискателя (также является окончательным). Это означает, что после вызова всех ваших методов onCreateViewHolder сохраняется только привязка данных последнего держателя представления, и все последующие onBindViewHolder методы вызывают bindView, передавая ссылку на привязку последнего viewholder.

RecyclerView перерабатывает видоискателей, что означает, что он не воссоздает их при изменении данных, а представления создаются только при первом вызове - поэтому он работает, когда вы снова открываете приложение или поворачиваете экран - onCreateViewHolder и onBindViewHolder вызываются по одной для каждой записи в вашем списке, правильное представление привязки.

Затем, когда данные изменяются и вы вызываете onDataSetChanged(), метод onCreateViewHolder никогда не вызывается, потому что у вас уже есть все ваши ViewHolder s, вызываются только 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();
    }
}
0 голосов
/ 01 апреля 2020

сначала вам нужно инициализировать адаптер 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();

        }
    }
});
0 голосов
/ 01 апреля 2020

Вы можете сделать одну вещь, добавить метод в класс адаптера, как показано ниже

public void updateData(ArrayList<Server> serversArrayList)
{
this.serversArrayList = serversArrayList;
notifyDataSetChanged();
}

, затем вызвать его из действия и просмотреть модель, как это

mAdapterForServers.updateData(serverArrayList);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...