问题
I have a two dimensional ArrayList
of type String
which is the input to the adapter class of the RecyclerView
. The data in the list is taken from an SQLite database everytime when onResume()
is called. I have implemented a drag and drop feature and an onMove()
function that swaps the list elements successfully. However, I need to store the modified list before onResume()
is called which will rewrite the list and fill it with old positions. My guess is to implement the rewriting functionality within the onStop()
event. This is my main 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);
}
It is important to update the database as long as I know when to store the data. How can I solve this problem? Any suggestions?
!!!
ANSWER:
Final solution I have implemented:
@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();
}
And inside of DB 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);
}
回答1:
You need a field in each DB row for storing the order. Then you need to implements those features:
On new row insert (when you insert a new object in database) you need to set the order field to the next int. You can get the current max value (with sql function
MAX
) and then simply do +1When user move an item in
RecyclerView
, in methodonMoved
you must update all other rows. You can use thefromPos
andtoPos
for that. More on that belowWhen you fill your
RecyclerView
with data you need to order them byorder
field
Explanation of 2nd feature to be implemented:
basically you need to update all rows with order between fromPos
and toPos
:
if user moved the item up (for example from position 4 to 2), you need to:
- get primary key field of current item (using position 4)
- change all rows between order 2 and order 4: so change 2 -> 3 and 3 -> 4
- Change current item order (using primary key of first point) to
toPos
: in this example change current item order to 2
if user moved the item down (for example from position 2 to 4) you need to:
- get primary key field of current item (using position 2)
- change all rows between order 2 and order 4: so change 4 -> 3 and 3 -> 2
- change current item order (using primary key of first point) to
toPos
: in this example change current item order to 4
Hope it helps a little
来源:https://stackoverflow.com/questions/38223107/store-new-position-of-recyclerview-items-in-sqlite-after-being-dragged-and-dropp