Info:
I have a RecyclerView
, and I populate it with the ArrayList dataList inside the ListAdapter
class. I get the data for dataList from the SQLiteDatabase
table: TABLE_USERdETAIL in the DbHelper
class. I'm trying to implement drag and drop re-organisation into the RecyclerView
by using the SimpleItemTouchHelperCallback
class; however, although I am now able to move the RecyclerView
elements, the list doesn't re-sort or move; I'm only able to temporarily drag the list elements over each other, as shown in the image below, but it's meant to be permanently slotting the list elements into whichever position it's held:
I expect the problem to be within the ListAdapter
class, inside the method onItemMove, but I don't know how to solve my issue.
Question: How do I make this drag and drop feature actually re-organise the RecyclerView
data list?
Update 5: I have updated my current code for further assistance.
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ListViewHolder> {
Context context;
List<UserData> dataList = new ArrayList<>();
LayoutInflater inflater;
Listener listener;
DbHelper dbHelper;
public interface Listener {
void nameToChnge(String name);
}
public ListAdapter(Context context, List<UserData> dataList1) {
this.context = context;
this.dataList = dataList1;
//this.listener= (Listener) context;
inflater = LayoutInflater.from(context);
}
@Override
public ListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View convertView = inflater.inflate(R.layout.recylerview_one, parent, false);
ListViewHolder viewHolder = new ListViewHolder(convertView);
return viewHolder;
}
@Override
public void onBindViewHolder(ListViewHolder holder, final int position) {
holder.tv_name.setText(dataList.get(position).name);
holder.tv_quantity.setText(dataList.get(position).quantity);
holder.tv_description.setText(dataList.get(position).description + " ");
if(dataList.get(position).description.isEmpty()) {
holder.tv_description.setVisibility(View.GONE);
}
holder.relLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String s = dataList.get(position).id;
Integer stringo = Integer.parseInt(s);
Intent intent = new Intent(context, ItemEditActivity.class);
intent.putExtra("ItemNumber", stringo);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return dataList.size();
}
class ListViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
TextView tv_name, tv_quantity, tv_description;
RelativeLayout relLayout;
public ListViewHolder(View itemView) {
super(itemView);
tv_name = (TextView) itemView.findViewById(R.id.nameDisplay);
tv_quantity = (TextView) itemView.findViewById(R.id.quantityDisplay);
tv_description = (TextView) itemView.findViewById(R.id.descriptionDisplay);
relLayout = (RelativeLayout) itemView.findViewById(R.id.relLayout);
}
@Override
public void onItemSelected() {
Log.d("ListViewHolder", "item selected");
}
@Override
public void onItemClear() {
Log.d("ListViewHolder", "item clear");
for (int count = 0; count < dataList.size(); count++) {
UserData u = dataList.get(count);
u.setSort(count);
dbHelper.updateUserData(u);
}
notifyDataSetChanged();
}
}
public void onItemDismiss(int position) {
dataList.remove(position);
//dbHelper = DbHelper.getInstance(context);
//dbHelper.deleteRowItem(position + 1);
notifyItemRemoved(position);
}
//Collections.swap(dataList, fromPosition, toPosition);
//notifyItemMoved(fromPosition, toPosition);
public boolean onItemMove(int fromPosition, int toPosition) {
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(dataList, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(dataList, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
return true;
}
}
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ListAdapter mAdapter;
public SimpleItemTouchHelperCallback(ListAdapter adapter) {
mAdapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {return true; }
@Override
public boolean isItemViewSwipeEnabled() { return false; }
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// We only want the active item to change
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder instanceof ItemTouchHelperViewHolder) {
// Let the view holder know that this item is being moved or dragged
Log.i("ADAPTER", "----DRAGGING----");
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (viewHolder instanceof ItemTouchHelperViewHolder) {
// Tell the view holder it's time to restore the idle state
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();
}
}
}
public class DbHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "UserDatabase";
private static final int DATABASE_VERSION = 2;
private static DbHelper mDbHelper;
public static String TABLE_USERdETAIL = "userdetail";
private static final String _ID = "_id";
private static final String SORT_ID = "sort_id";
private static final String NAME = "name";
private static final String QUANTITY = "quantity";
private static final String WEIGHT = "weight";
private static final String WEIGHTTOTAL = "weighttotal";
private static final String VALUE = "value";
private static final String VALUETOTAL = "valuetotal";
private static final String DESCRIPTION = "description";
public static synchronized DbHelper getInstance(Context context) {
if (mDbHelper == null) {
mDbHelper = new DbHelper(context.getApplicationContext());
}
return mDbHelper;
}
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_USERDETAIL_TABLE = "CREATE TABLE " + TABLE_USERdETAIL +
"(" +
_ID + " INTEGER PRIMARY KEY , " +
SORT_ID + " INTEGER," +
NAME + " TEXT," +
QUANTITY + " INTEGER," +
WEIGHT + " INTEGER," +
WEIGHTTOTAL + " INTEGER," +
VALUE + " INTEGER," +
VALUETOTAL + " INTEGER," +
DESCRIPTION + " TEXT" +
")";
db.execSQL(CREATE_USERDETAIL_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
db.execSQL("ALTER TABLE " + TABLE_USERdETAIL + " ADD COLUMN " + WEIGHT + " INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE_USERdETAIL + " ADD COLUMN " + WEIGHTTOTAL + " INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE_USERdETAIL + " ADD COLUMN " + VALUE + " INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE_USERdETAIL + " ADD COLUMN " + VALUETOTAL + " INTEGER DEFAULT 0");
}
}
/**
Insert a user detail into database
*/
public void insertUserDetail(UserData userData) {
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
ContentValues values = new ContentValues();
values.put(SORT_ID, userData.sort_id);
values.put(NAME, userData.name);
values.put(QUANTITY, userData.quantity);
values.put(WEIGHT, userData.weight);
values.put(WEIGHTTOTAL, userData.weighttotal);
values.put(VALUE, userData.value);
values.put(VALUETOTAL, userData.valuetotal);
values.put(DESCRIPTION, userData.description);
db.insertOrThrow(TABLE_USERdETAIL, null, values);
db.setTransactionSuccessful();
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
}
public void updateUserDetail(int id, String v1, String v2, String v3, String v4, String v5, String v6, String v7){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(NAME, v1);
values.put(QUANTITY, v2);
values.put(DESCRIPTION, v3);
values.put(WEIGHT, v4);
values.put(WEIGHTTOTAL, v5);
values.put(VALUE, v6);
values.put(VALUETOTAL, v7);
db.update(TABLE_USERdETAIL, values, "_id="+id, null);
}
/**
fetch all data from UserTable
*/
public List<UserData> getAllUser() {
List<UserData> usersdetail = new ArrayList<>();
String USER_DETAIL_SELECT_QUERY = "SELECT * FROM " + TABLE_USERdETAIL + " ORDER BY " + SORT_ID + " COLLATE NOCASE;";
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.rawQuery(USER_DETAIL_SELECT_QUERY, null);
try {
if (cursor.moveToFirst()) {
do {
UserData userData = new UserData();
userData.id = cursor.getString(cursor.getColumnIndex(_ID));
userData.sort_id = cursor.getInt(cursor.getColumnIndex(SORT_ID));
userData.name = cursor.getString(cursor.getColumnIndex(NAME));
userData.quantity = "Quantity: " + cursor.getString(cursor.getColumnIndex(QUANTITY));
userData.weight = cursor.getString(cursor.getColumnIndex(WEIGHT));
userData.weighttotal = cursor.getString(cursor.getColumnIndex(WEIGHTTOTAL));
userData.value = cursor.getString(cursor.getColumnIndex(VALUE));
userData.valuetotal = cursor.getString(cursor.getColumnIndex(VALUETOTAL));
userData.description = cursor.getString(cursor.getColumnIndex(DESCRIPTION));
usersdetail.add(userData);
} while (cursor.moveToNext());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
return usersdetail;
}
/**
Delete single row from UserTable
*/
void deleteRow(String name) {
SQLiteDatabase db = getWritableDatabase();
try {
db.beginTransaction();
db.execSQL("delete from " + TABLE_USERdETAIL + " where name ='" + name + "'");
db.setTransactionSuccessful();
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
}
void deleteRowItem(int id) {
SQLiteDatabase db = getWritableDatabase();
try {
db.beginTransaction();
db.execSQL("delete from " + TABLE_USERdETAIL + " where _id ='" + id + "'");
db.setTransactionSuccessful();
} catch (SQLException e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
}
public UserData getSingleUserDetail(String userId) {
SQLiteDatabase db = this.getWritableDatabase();
UserData userData = null;
//Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_USERdETAIL, null);
// this is the code to order the RecyclerView by _ID:
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_USERdETAIL + " WHERE " + _ID + "= ?", new String[]{userId});
try {
while (cursor.moveToNext()) {
userData = new UserData();
userData.name = cursor.getString(cursor.getColumnIndex(NAME));
userData.quantity = cursor.getString(cursor.getColumnIndex(QUANTITY));
userData.weight = cursor.getString(cursor.getColumnIndex(WEIGHT));
userData.weighttotal = cursor.getString(cursor.getColumnIndex(WEIGHTTOTAL));
userData.value = cursor.getString(cursor.getColumnIndex(VALUE));
userData.valuetotal = cursor.getString(cursor.getColumnIndex(VALUETOTAL));
userData.description = cursor.getString(cursor.getColumnIndex(DESCRIPTION));
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
return userData;
}
public int getTotalWeight() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor cur = db.rawQuery("SELECT SUM(WEIGHTTOTAL) FROM userdetail", null);
if(cur.moveToFirst())
{
return cur.getInt(0);
}
cur.close();
return getTotalWeight();
}
public int getTotalQuantity() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor cur = db.rawQuery("SELECT SUM(QUANTITY) FROM userdetail", null);
if(cur.moveToFirst())
{
return cur.getInt(0);
}
cur.close();
return getTotalQuantity();
}
public int getTotalValue() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor cur = db.rawQuery("SELECT SUM(VALUETOTAL) FROM userdetail", null);
if(cur.moveToFirst())
{
return cur.getInt(0);
}
cur.close();
return getTotalValue();
}
public int getMaxColumnData() {
SQLiteDatabase db = this.getWritableDatabase();
final SQLiteStatement stmt = db
.compileStatement("SELECT MAX(SORT_ID) FROM " + TABLE_USERdETAIL);
return (int) stmt.simpleQueryForLong();
}
public void updateUserData(UserData userData) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(NAME, userData.getName());
values.put(QUANTITY, userData.getQuantity());
values.put(DESCRIPTION, userData.getDescription());
values.put(WEIGHT, userData.getWeight());
values.put(WEIGHTTOTAL, userData.getWeighttotal());
values.put(VALUE, userData.getValue());
values.put(VALUETOTAL, userData.getValuetotal());
values.put(SORT_ID, userData.getSort());
Log.i("DBhelper", "USER UPDATED = " + userData.getName());
db.update(TABLE_USERdETAIL, values, _ID + "=?", new String[]{String.valueOf(userData.getId())});
}
}
import java.io.Serializable;
public class UserData implements Serializable {
String id, name, quantity, weight, weighttotal, value, valuetotal, description;
int sort_id;
public UserData() {
super();
}
public void setId(String id){
this.id= id;
}
public String getId(){
return id;
}
public void setSort(int sort){
this.sort_id= sort;
}
public int getSort(){
return sort_id;
}
public void setName(String name){
this.name= name;
}
public String getName(){
return name;
}
public void setDescription(String description){
this.description= description;
}
public String getDescription(){
return description;
}
public void setQuantity(String quantity){
this.quantity= quantity;
}
public String getQuantity(){
return quantity;
}
public void setWeight(String weight){
this.weight= weight;
}
public String getWeight(){
return weight;
}
public void setWeighttotal(String weighttotal){
this.weighttotal= weighttotal;
}
public String getWeighttotal(){
return weighttotal;
}
public void setValue(String value){
this.value= value;
}
public String getValue(){
return value;
}
public void setValuetotal(String valuetotal){
this.quantity= valuetotal;
}
public String getValuetotal(){
return quantity;
}
}
public interface ItemTouchHelperViewHolder {
void onItemSelected();
void onItemClear();
}
public class MainActivity extends AppCompatActivity implements ListAdapter.Listener {
RecyclerView recyclerView;
DbHelper dbHelper;
ListAdapter adapter;
private ItemTouchHelper mItemTouchHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = DbHelper.getInstance(getApplicationContext());
recyclerView = (RecyclerView) findViewById(R.id.rv_contactlist);
adapter = new ListAdapter(this, dbHelper.getAllUser());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ItemTouchHelper.Callback callback =
new SimpleItemTouchHelperCallback(adapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.about_task:
Intent intentChangeActivity2 = new Intent(MainActivity.this, AboutActivity.class);
startActivity(intentChangeActivity2);
return true;
case R.id.encumbrance_task:
Intent intentChangeActivity = new Intent(MainActivity.this, EncumbranceActivity.class);
startActivity(intentChangeActivity);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onResume() {
super.onResume();
dbHelper = DbHelper.getInstance(getApplicationContext());
recyclerView = (RecyclerView) findViewById(R.id.rv_contactlist);
adapter = new ListAdapter(this, dbHelper.getAllUser());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
@Override
public void nameToChnge(String name) {
dbHelper.deleteRow(name);
adapter = new ListAdapter(this, dbHelper.getAllUser());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
}
8-26 11:20:49.443 23533-23533/name.appE/AndroidRuntime: FATAL EXCEPTION: main
Process: name.app, PID: 23533
java.lang.NullPointerException: Attempt to invoke virtual method 'void name.app.DbHelper.updateUserData(name.app.UserData)' on a null object reference
at name.app.ListAdapter$ListViewHolder.onItemClear(ListAdapter.java:95)
at name.app.SimpleItemTouchHelperCallback.clearView(SimpleItemTouchHelperCallback.java:63)
at android.support.v7.widget.helper.ItemTouchHelper$3.onAnimationEnd(ItemTouchHelper.java:619)
at android.support.v4.animation.HoneycombMr1AnimatorCompatProvider$AnimatorListenerCompatWrapper.onAnimationEnd(HoneycombMr1AnimatorCompatProvider.java:115)
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1149)
at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1309)
at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
at android.animation.AnimationHandler.-wrap2(AnimationHandler.java)
at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:869)
at android.view.Choreographer.doCallbacks(Choreographer.java:683)
at android.view.Choreographer.doFrame(Choreographer.java:616)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Drag and Drop can be added in a RecyclerView using the ItemTouchHelper utility class. Following are the important methods in the ItemTouchHelper. Callback interface which needs to be implemented: isLongPressDragEnabled - return true here to enable long press on the RecyclerView rows for drag and drop.
I'm not sure that catching your problem but what i noticed (hope this helps):
in your onItemMove
you are refactoring dataList
by swapping items but adapter notifies only about general change.
guess the simplest way to move the item (and save animation) is to remove it and add again:
UserData item = dataList.remove(fromPosition);
dataList.add(i, toPossition);
notifyItemMoved(fromPosition, toPosition);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With