将 RecyclerView 项目拖放后在 SQLite 中的新位置存储

Store new position of RecyclerView items in SQLite after being dragged and dropped

我有一个 String 类型的二维 ArrayList,它是 RecyclerView 的适配器 class 的输入。每次调用 onResume() 时,列表中的数据都取自 SQLite 数据库。我已经实现了拖放功能和 onMove() 功能,可以成功交换列表元素。但是,我需要在调用 onResume() 之前存储修改后的列表,这将重写列表并用旧位置填充它。我的猜测是在 onStop() 事件中实现重写功能。这是我的主要 activity:

RecyclerView recyclerView;
RecyclerViewAdapter adapter;
RecyclerView.LayoutManager layoutManager;

ArrayList<ArrayList<String>> data;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    assert fab != null;
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent i = new Intent(MainActivity.this, ViewDbActivity.class);
            startActivity(i);
        }
    });

    recyclerView = (RecyclerView) findViewById(R.id.myRecyclerView);
    layoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(layoutManager);
    RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();

    ItemTouchHelper item = new ItemTouchHelper(new ItemTouchHelper.Callback() {

        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            int swipeFlags = ItemTouchHelper.RIGHT;
            return makeMovementFlags(dragFlags, swipeFlags);
        }

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            Collections.swap(data, viewHolder.getAdapterPosition(), target.getAdapterPosition());
            adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
            return true;
        }

        @Override
        public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
            super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
            Toast.makeText(MainActivity.this, "Moved", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            data.remove(viewHolder.getAdapterPosition());
            adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
        }
    });

    item.attachToRecyclerView(recyclerView);
    recyclerView.setItemAnimator(itemAnimator);
}

@Override
protected void onResume() {
    super.onResume();

    initialize();

    if(adapter == null) {
        Log.v(TAG, "Adapter = NULL. Initialized");
        setAdapter();
    }
    else {
        Log.v(TAG, "notify is called");
        adapter.updateData(data);
    }
}

public void initialize() {
    Database ourDB = new Database(this);
    ourDB.openDB();
    data = ourDB.getData();
    ourDB.closeDB();
}

public void setAdapter() {
    adapter = new RecyclerViewAdapter(data, this);
    recyclerView.setAdapter(adapter);
}

只要我知道何时存储数据,更新数据库就很重要。我怎么解决这个问题?有什么建议吗?

!!!

答案:

我实现的最终解决方案:

@Override
public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
    super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);

    //preparing new position values
    long movedItem = Long.parseLong(data.get(fromPos).get(0));     // .get(fromPos).get(0) returns PRIMARY KEY from the list
    long draggedItem = Long.parseLong(data.get(toPos).get(0));

    // updating affected rows with new orders
    Database db = new Database(MainActivity.this);
        db.open();
        db.updateOrder(draggedItem, toPos);
        db.updateOrder(movedItem, fromPos);
        db.close();
}

和数据库内部 class:

public void updateOrder(long rowID, int newPos) {
    ContentValues cv = new ContentValues();
    cv.put(KEY_ORDER, newPos);
    ourDatabase.update(DATABASE_TABLE, cv, KEY_ROWID + "=" + rowID, null);
}

您需要在每个数据库行中有一个字段来存储订单。 然后你需要实现这些功能:

  • 在插入新行时(当您在数据库中插入新对象时),您需要将 order 字段设置为下一个整数。您可以获得当前最大值(使用 sql 函数 MAX)然后简单地执行 +1

  • 当用户在 RecyclerView 中移动项目时,在方法 onMoved 中,您必须更新所有其他行。您可以为此使用 fromPostoPos。更多内容见下文

  • 当您用数据填充 RecyclerView 时,您需要按 order 字段对它们进行排序



要实现的第二个功能的说明: 基本上你需要更新顺序在 fromPostoPos:

之间的所有行
  • 如果用户将项目向上移动(例如从位置 4 到 2),您需要:

    1. 获取当前项目的主键字段(使用位置 4)
    2. 更改顺序 2 和顺序 4 之间的所有行:因此更改 2 -> 3 和 3 -> 4
    3. 将当前项目顺序(使用第一点的主键)更改为toPos:在此示例中,将当前项目顺序更改为 2
  • 如果用户将项目向下移动(例如从位置 2 到 4),您需要:

    1. 获取当前项目的主键字段(使用位置 2)
    2. 更改订单 2 和订单 4 之间的所有行:因此更改 4 -> 3 和 3 -> 2
    3. 将当前项目顺序(使用第一点的主键)更改为toPos:在此示例中,将当前项目顺序更改为 4


希望能有点帮助