При установке флажка он обновляет другие строки в представлении реселлера. DiffUtils и DataBinding используются для обновления и привязки данных - PullRequest
0 голосов
/ 24 апреля 2020

Я пытаюсь реализовать приложение создания задач. Пользователь должен иметь возможность проверить задание, чтобы пометить его как выполненное. Но когда в окне повторного просмотра нажимается флажок более чем одного держателя, он начинает обновлять другие строки. Предположим, у меня есть 3 строки - A, B, C, я проверяю флажок A, и когда я проверяю флажок B, тогда начинают происходить странные вещи, заголовок строки A меняется на, и теперь у меня есть 2 элемента с заголовком B. И когда я снимаю флажок с B, он также снимает флажок с A. Так вот мой код. Этот беспорядок прекращается, когда в методе equals я убираю проверку Object.equals (завершено, task.completed). Но в этом случае не вызывается функция setStyle, которая отвечает за рисование обводки в текстовом представлении.


@Entity(tableName = "tasks")
public class Task {
    @ColumnInfo(name = "title")
    String title;

    public String getDescr() {
        return descr;
    }

    @ColumnInfo(name = "description")
    String descr;
    @ColumnInfo(name = "completed")
    boolean completed = false;

    @ColumnInfo(name = "task_date")
    String taskDate;
    @ColumnInfo(name = "task_deadline")
    String taskDeadline;


    @NonNull
    @PrimaryKey
    @ColumnInfo(name = "taskId")
    String id;

    public Task(String title, String descr, boolean completed) {
        this.title = title;
        this.descr = descr;
        this.completed = completed;
        id = UUID.randomUUID().toString();
    }

    public Task(String title, String descr, String date, boolean completed) {
        this.title = title;
        this.descr = descr;
        this.completed = completed;
        this.taskDate = date;
        id = UUID.randomUUID().toString();
    }


    public Task(String title, String descr, String date, String time, boolean completed) {
        this.title = title;
        this.descr = descr;
        this.completed = completed;
        this.taskDate = date;
        this.taskDeadline = time;
        id = UUID.randomUUID().toString();
    }

    public boolean isEmpty() {
        return title.isEmpty() || descr.isEmpty();
    }

    public boolean isActive() {
        return !completed;
    }

    public boolean isCompleted() {
        return completed;
    }

    @NonNull
    public String getId() {
        return id;
    }


    public String getTaskDeadline() {
        return taskDeadline;
    }

    public void setId(@NonNull String id) {
        this.id = id;
    }

    public String getTitle() {
        return title != null ? title : descr;
    }

    public String getTaskDate() {
        return taskDate != null ? taskDate : "";
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Task task = (Task) o;
        return Objects.equals(id, task.id) && Objects.equals(title, task.title) &&
                Objects.equals(descr, task.descr) && Objects.equals(completed, task.completed);
    }
}


publi c класс TasksAdapter расширяет ListAdapter {

private ItemTaskBinding binding;
private final TaskViewModel mViewModel;

TasksAdapter(TaskViewModel viewModel) {
    super(DIFF_CALLBACK);
    mViewModel = viewModel;
}

@NonNull
@Override
public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    binding = ItemTaskBinding.inflate(layoutInflater, parent, false);
    return new TaskViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull TaskViewHolder holder, int position) {
    Task item = getItem(position);
    holder.bind(mViewModel, item);
}

class TaskViewHolder extends RecyclerView.ViewHolder {
    private TaskViewHolder(ItemTaskBinding binding) {
        super(binding.getRoot());
    }

    void bind(TaskViewModel viewModel, Task item) {
        binding.setViewModel(viewModel);
        binding.setTask(item);
        binding.executePendingBindings();
    }
}

private static final DiffUtil.ItemCallback<Task> DIFF_CALLBACK = new DiffUtil.ItemCallback<Task>() {

    @Override
    public boolean areItemsTheSame(@NonNull Task oldItem, @NonNull Task newItem) {
        return oldItem.getId().equals(newItem.getId());
    }

    @Nullable
    @Override
    public Object getChangePayload(@NonNull Task oldItem, @NonNull Task newItem) {
        return super.getChangePayload(oldItem, newItem);

    }

    @Override
    public boolean areContentsTheSame(@NonNull Task oldItem, @NonNull Task newItem) {
        return  oldItem.equals(newItem);
    }
};

}

И это XML

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="android.widget.CompoundButton" />

        <variable
            name="viewModel"
            type="com.example.taskmanagement.tasks.TaskViewModel" />

        <variable
            name="task"
            type="com.example.taskmanagement.room.Task" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/rounded_border_white"
        android:onClick="@{() -> viewModel.openTaskToUpdate(task)}"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:paddingEnd="12dp"
        android:paddingStart="12dp"
        android:paddingBottom="8dp"
        android:layout_marginBottom="8dp">

        <CheckBox
            android:id="@+id/completed_checkBox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:checked="@{task.completed}"
            android:onClick="@{(view) -> viewModel.completeTask(task, ((CompoundButton)view).isChecked())}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="10dp"/>


        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="15dp"
            android:layout_marginLeft="15dp"
            android:text="@{task.title}"
            android:textAppearance="@style/TextAppearance.AppCompat.Title"
            app:completedTask="@{task.completed}"
            app:layout_constraintStart_toEndOf="@+id/completed_checkBox"
            app:layout_constraintTop_toTopOf="@id/completed_checkBox"
            android:layout_marginEnd="5dp"
            android:layout_marginRight="5dp"
            tools:text="aaaaaaaaaaa" />

        <TextView
            android:id="@+id/description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{task.descr!=null? task.descr : "" }'
            app:layout_constraintStart_toStartOf="@id/title"
            app:layout_constraintTop_toBottomOf="@id/title"
            tools:text="aaaaaaaaa" />

        <TextView
            android:id="@+id/task_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="@{task.taskDeadline}"
            app:layout_constraintStart_toEndOf="@id/task_date"
            app:layout_constraintTop_toTopOf="@id/task_date"
            tools:text="15:30" />

        <TextView
            android:id="@+id/task_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="5dp"
            android:drawableLeft="@drawable/choose_date_resized"
            android:drawablePadding="5dp"
            android:text="@{task.taskDate}"
            app:layout_constraintStart_toStartOf="@id/completed_checkBox"
            app:layout_constraintTop_toBottomOf="@id/description"
            tools:text="12/16/2020" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>



Это модель представления


    private static TasksRepository mTaskRepository;
    private static MutableLiveData<List<Task>> allItemsMutableLiveData = new MutableLiveData<>();
    private static MutableLiveData<List<Task>> completedItemsMutableLiveData = new MutableLiveData<>();

    private MutableLiveData<Event<String>> _isTaskClicked = new MutableLiveData<>();
    private static List<Task> listOfTasks;
    private static List<Task> listOfCompletedTasks;

    private static final CompositeDisposable mDisposable = new CompositeDisposable();


    LiveData<Event<String>> getIsTaskClicked() {
        return _isTaskClicked;
    }

    TaskViewModel(TasksRepository taskRepository) {
        mTaskRepository = taskRepository;
        getListOfTasks();
    }

    public void openTaskToUpdate(Task task) {
        _isTaskClicked.setValue(new Event(task.getId())); // Trigger the event by setting a new Event as a new value
    }

    private static void getListOfTasks() {
        mDisposable.add(mTaskRepository.getAllTasksFromDB().map(taskList -> {
                    listOfTasks = taskList;
                    return listOfTasks;
                }).observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Consumer<List<Task>>() {
                            @Override
                            public void accept(List<Task> taskList) throws Exception {
                                allItemsMutableLiveData.setValue(taskList);
                            }
                        })
        );
    }

    public static LiveData<List<Task>> getItems() {
        if (allItemsMutableLiveData.getValue() != null) {
            for (int i = 0; i < allItemsMutableLiveData.getValue().size(); i++) {
                Timber.d("task" + i + allItemsMutableLiveData.getValue().get(i).getTitle());
            }
        }
        return allItemsMutableLiveData;

    }

    void getAllActiveTasks() {
        mDisposable.add(mTaskRepository.getAllActiveTasks().subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<List<Task>>() {
                    @Override
                    public void accept(List<Task> taskList) throws Exception {
                        allItemsMutableLiveData.setValue(taskList);
                    }
                }));
    }

    public static LiveData<List<Task>> getCompletedItems() {
        mDisposable.add(mTaskRepository.getAllCompletedTasks()
                .observeOn(Schedulers.io()).map(taskList -> {
                    listOfCompletedTasks = taskList;
                    return listOfCompletedTasks;
                }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<List<Task>>() {
                    @Override
                    public void accept(List<Task> taskList) throws Exception {
                        completedItemsMutableLiveData.setValue(listOfCompletedTasks);
                    }
                }));

        return completedItemsMutableLiveData;
    }

    void deleteAllTasks() {
        mDisposable.add(Completable.fromAction(new Action() {
            @Override
            public void run() throws Exception {
                mTaskRepository.deleteAllTasks();
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe());
    }


    public void completeTask(Task task, Boolean isChecked) {
        if (isChecked) {
            mDisposable.add(Completable.fromAction(() -> mTaskRepository.completeTask(task.getId(), true))
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()).subscribe());
        } else {
            mDisposable.add(Completable.fromAction(() -> mTaskRepository.activateTask(task.getId()))
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()).subscribe());
        }
    }


    @Override
    protected void onCleared() {
        mDisposable.clear();
        super.onCleared();
    }
}
...