Я пытаюсь использовать ItemTouchHelper для проведения операций перетаскивания и перетаскивания в обзоре переработчика. Данные поступают из базы данных Android. Его методы должны быть асинхронными.
Я не могу использовать ListAdapter в представлении реселлера, потому что он вызывает другие методы, а затем notifyItemMoved. Это позволило бы перетаскивать действия drag'n'drop в ItemTouchHelper, см. ItemTouchHelper - Отбрасывание принудительно после первой строки перехода . В конце я должен реализовать свой собственный адаптер и сам позаботиться о функциях уведомлений.
Я последовал этому примеру , чтобы ItemTouchHelper работал с Android Room, который выглядит следующим образом:
private CategoryAdapter categoryAdapter;
private DaoCategory daoCategory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.category_activity);
setTitle(R.string.edit_categories);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
daoCategory = DataBase.Companion.getInstance(this.getApplicationContext()).getDaoCategory();
categoryAdapter = new CategoryAdapter(new ArrayList<>(daoCategory.getCategoriesAscending()));
recyclerView.setAdapter(categoryAdapter);
updateList(() -> {
});
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
moveCategory(categoryAdapter.getCatList().get(viewHolder.getAdapterPosition()), viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
CategoryViewHolder categoryViewHolder = (CategoryViewHolder) viewHolder;
deleteCategory(categoryAdapter.getCatList().get(categoryViewHolder.getAdapterPosition()), categoryViewHolder.getAdapterPosition());
}
});
itemTouchHelper.attachToRecyclerView(recyclerView);
FloatingActionButton floatingActionButton = findViewById(R.id.fab);
floatingActionButton.setOnClickListener(v -> {
saveCategory(new Category(String.valueOf(System.currentTimeMillis())));
});
}
private void updateList(Callback callback) {
new AsyncTask<Void, Void, List<Category>>() {
@Override
protected List<Category> doInBackground(Void... params) {
return daoCategory.getCategoriesAscending();
}
@Override
protected void onPostExecute(List<Category> categories) {
categoryAdapter.setCatList(new ArrayList<>(categories));
callback.callback();
}
}.execute();
}
interface Callback {
void callback();
}
private void deleteCategory(final Category category, final int oldpos) {
new AsyncTask<Category, Void, Void>() {
@Override
protected Void doInBackground(Category... params) {
daoCategory.deleteCategory(category.getName());
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
updateList(() -> categoryAdapter.notifyItemRemoved(oldpos));
}
}.execute();
}
private void moveCategory(final Category category, final int oldPos, final int newPos) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
daoCategory.moveCategory(category.getName(), newPos);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
updateList(() -> categoryAdapter.notifyItemMoved(oldPos, newPos));
}
}.execute();
}
private void saveCategory(final Category category) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
daoCategory.saveCategory(category);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
updateList(() -> categoryAdapter.notifyItemInserted(categoryAdapter.getItemCount() - 1));
}
}.execute();
}
Особенно при drag'n'drop, когда вызывается moveCategory, метод вызывается так быстро, что все вылетает с «IndexOutOfBoundsException: Обнаружено несоответствие. Неверный адаптер держателя представления». Расовые условия.
Есть идеи, как я могу это легко исправить? Решение, которое я вижу здесь, состоит в том, чтобы получить все методы категории daoCategory. [...], выполняющие мьютекс и в правильном порядке. Это может быть достигнуто с помощью очереди потоков (может быть ограничено 3-5 пунктами). Категория Adapter. [...] вещи будут запускаться OnUiThread. Я надеюсь, что "синхронизированный" охватывает это тоже.
С другой стороны, я могу заставить его работать легко, когда разрешаюMainThreadQueries (), который не предназначен для использования. Это может означать, что пользовательский интерфейс зависает при запросах (некоторые методы daoCategory состоят из множества запросов, например, moveCategory).
Какой подход вы бы выбрали? Я пропускаю какие-либо очевидные решения?