我正在尝试实现一个任务创建应用程序。用户应该能够检查任务以将其标记为已完成。但是,当在 recyclerview 中按下多个视图的复选框时,它会开始更新其他行。假设我有 3 行 - A,B,C ,我选中 A 的复选框,当我选中 B 的复选框时,奇怪的事情开始发生,A 的行标题更改为,现在我有 2 个项目的标题为 B。当我取消选中 B 时,它也会取消选中 A。所以这是我的代码。当我在 equals 方法中删除 Object.equals(completed, task.completed) 检查时,这种混乱就停止了。但在这种情况下,不会调用 setStyle 函数,它负责在 textview 上绘制笔画。
@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);
}
}
公共类 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();
}
}