Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/218.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android:在RecyclerView中拖放项目时,如何有效地更新SQLite数据库?_Java_Android_Sqlite_Android Asynctask_Background - Fatal编程技术网

Java Android:在RecyclerView中拖放项目时,如何有效地更新SQLite数据库?

Java Android:在RecyclerView中拖放项目时,如何有效地更新SQLite数据库?,java,android,sqlite,android-asynctask,background,Java,Android,Sqlite,Android Asynctask,Background,我有这个待办事项列表应用程序,其中“任务”可以包含自己的“子任务”列表。问题是,每当这些“任务”通过拖放重新排列时,有时会给我一些奇怪的行为,比如在单击它们以显示其子列表时崩溃 以下是拖放侦听器的代码: private void attachItemTouchHelperToAdapter() { ItemTouchHelper.SimpleCallback touchCallback = new ItemTouchHelper.SimpleCallback(It

我有这个待办事项列表应用程序,其中“任务”可以包含自己的“子任务”列表。问题是,每当这些“任务”通过拖放重新排列时,有时会给我一些奇怪的行为,比如在单击它们以显示其子列表时崩溃

以下是拖放侦听器的代码:

private void attachItemTouchHelperToAdapter() {
    ItemTouchHelper.SimpleCallback touchCallback =
            new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
                    ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
                @Override
                public boolean onMove(RecyclerView recyclerView,
                                      RecyclerView.ViewHolder viewHolder,
                                      RecyclerView.ViewHolder target) {
                    final int fromPosition = viewHolder.getAdapterPosition();
                    final int toPosition = target.getAdapterPosition();
                    rearrangeTasks(fromPosition, toPosition);

                    // Call background thread to update database.
                    new UpdateDatabaseTask(mTaskList).execute();
                    return true;
                }

                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                    int position = viewHolder.getAdapterPosition();
                    Task taskToDelete = mTaskAdapter.mTasks.get(position);
                    TaskLab.get(getActivity()).deleteTask(taskToDelete);
                    updateUI(position);
                }
            };

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(touchCallback);
    itemTouchHelper.attachToRecyclerView(mTaskRecyclerView);
}
重新排列onMove中调用的列表的代码:

private void rearrangeTasks(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(mTaskList, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(mTaskList, i, i - 1);
        }
    }
    mTaskAdapter.notifyItemMoved(fromPosition, toPosition);
}
调用数据库帮助程序函数,以使用重新排列的列表更新整个表:

public void updateDatabase(List<Task> tasks) {
    mDatabase.delete(TaskTable.NAME, null, null);
    for (Task task : tasks) {
        addTask(task);
    }
}
public void updateDatabase(列出任务){
mDatabase.delete(TaskTable.NAME,null,null);
for(任务:任务){
添加任务(task);
}
}
这里的问题是,有时,当快速拖放“任务”时,AsyncTask更新数据库的速度不够快,因此当我试图在数据库完成更新之前对其执行函数时,会出现奇怪的行为


<> P> > SQLite数据库更新的更好方法是什么?<代码> RealReVIEW < /代码>是拖放的?

< P>这个问题太宽泛,无法回答,因为在解决您的问题时,您可以考虑几种解决方案。我现在可以想到两个,下面我将简要介绍一下

解决方案#1

可以考虑调用数据库方法直接更新表,而不必通过<代码> AycCastase调用它。在数据库表中注册内容观察者,以便每次更新表时,

RecyclerView
都会随之更新,而无需调用
notifyDataSetChanged()
。示例实现应该如下所示

public class Task {
    public int taskId;
    public int taskPosition; 
}

public void updateDatabase(Task taskToBeUpdated, int newPosition) {

     // You need two update queries. 
     // Update task_table set task_position += task_position + 1 where task_position >= newPosition;
     // Update task_table set task_position = newPosition where taskId = taskTobeUpdated.taskId
}
像这样声明数据库表的URI

public static final Uri DB_TABLE_TASKS_URI = Uri
            .parse("sqlite://" + Constants.ApplicationPackage + "/" + DB_TABLE_TASKS);
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    return new SQLiteCursorLoader(getActivity()) {
        @Override
        public Cursor loadInBackground() {

            Cursor cursor;
            cursor = TasksLab.getTasks();

            // Register the cursor with the content observer
            this.registerContentObserver(cursor, DBConstants.DB_TABLE_TASKS_URI);
            return cursor;
        }
    };
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Set the cursor in the adapter of your RecyclerView here. 
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {

}

// Do not forget to destroy the loader when you are destroying the view.
@Override
public void onDestroy() {
    getLoaderManager().destroyLoader(TASKS_QUERY_LOADER);
    super.onDestroyView();
}
现在,在您的
updateDatabase
函数中,您需要调用此notify函数,在任务表发生更改或更新时通知正在收听此内容的观察者

public static void updateDatabase(List<Task> taskList) {
    // .. Your other implementation goes here 
    context.getContentResolver().notifyChange(DBConstants.DB_TABLE_TASKS_URI, null);
}
现在,您需要在
TasksActivity
中实现
LoaderCallbacks
的功能。一个示例实现应该是这样的

public static final Uri DB_TABLE_TASKS_URI = Uri
            .parse("sqlite://" + Constants.ApplicationPackage + "/" + DB_TABLE_TASKS);
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    return new SQLiteCursorLoader(getActivity()) {
        @Override
        public Cursor loadInBackground() {

            Cursor cursor;
            cursor = TasksLab.getTasks();

            // Register the cursor with the content observer
            this.registerContentObserver(cursor, DBConstants.DB_TABLE_TASKS_URI);
            return cursor;
        }
    };
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Set the cursor in the adapter of your RecyclerView here. 
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {

}

// Do not forget to destroy the loader when you are destroying the view.
@Override
public void onDestroy() {
    getLoaderManager().destroyLoader(TASKS_QUERY_LOADER);
    super.onDestroyView();
}
现在,当您离开
TaskActivity
时,您需要将更改保存到数据库中

@Override
public void onDestroy() {
    updateDatabaseFromTheList();
    super.onDestroyView();
}

@Override
public void onPause() {
    updateDatabaseFromTheList();
    super.onDestroyView();
}
并在
onResume
函数中每次从数据库加载任务

@Override
public void onResume() {
    super.onResume();
    updateRecyclerViewFromDatabase();
}
更新

基于上述评论中解决方案1所需的澄清

“我建议只传递被拖动或删除的任务id 更新,以便表立即得到更新。“。我该怎么办 这样做

我不确定您现在是如何更新任务表的。然而,我可以想到一些我自己的实现。只需将要更新的任务传递给它在任务表中的位置。因此,伪实现可能如下所示

public class Task {
    public int taskId;
    public int taskPosition; 
}

public void updateDatabase(Task taskToBeUpdated, int newPosition) {

     // You need two update queries. 
     // Update task_table set task_position += task_position + 1 where task_position >= newPosition;
     // Update task_table set task_position = newPosition where taskId = taskTobeUpdated.taskId
}

希望这能有所帮助。

感谢您付出这么多努力来回答这个问题。您说过,“我建议只传递被拖动或更新的任务id,以便表立即得到更新。”。我该怎么做?