问题
I'm storing text items in a RecyclerView adapter and in a Content Provider. The list is accessible from the menu option. Items are deleted by swiping. Currently, the items are being saved, but not deleted. I've debugged and it shows that the "id" is 0(isn't being retrieved in the Main Activity):
int id = (int) viewHolder.itemView.getTag();
The selected item isn't being swiped off the screen. I'm basing my code on this structure:
https://www.javatips.net/api/ud851-Exercises-master/ud851-Exercises-student/Lesson09-ToDo-List/T09.07-Solution-SwipeToDelete/app/src/main/java/com/example/android/todolist/MainActivity.java
I've looked at this thread and the linked threads in that post and my code should work. It worked before in another project. Is the issue with the cursor in the Favorites Adapter class? Thank you in advance.
Swipe to Dismiss for RecyclerView
As well as this thread:
Deleting Row in SQLite in Android
onSwiped and Loader Cursor methods in the Main Activity:
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT| ItemTouchHelper.RIGHT)
{
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
{
return false;
}
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof LinesAdapter.LinesAdapterViewHolder) return 0;
return super.getSwipeDirs(recyclerView, viewHolder);
}
// Called when a user swipes left or right on a ViewHolder
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// Here is where you'll implement swipe to delete
//Construct the URI for the item to delete
//[Hint] Use getTag (from the adapter code) to get the id of the swiped item
// Retrieve the id of the task to delete
int id = (int) viewHolder.itemView.getTag();
// Build appropriate uri with String row id appended
String stringId = Integer.toString(id);
Uri uri = TubeLineContract.TubeLineEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
int rowsDeleted = getContentResolver().delete(uri,null, null);
Log.v("CatalogActivity", rowsDeleted + " rows deleted from the line database");
getSupportLoaderManager().restartLoader(FAVORITES_LOADER_ID, null, MainActivity.this);
}
}).attachToRecyclerView(mLineRecyclerView);
/*
* Starting the asyncTask so that lines load upon launching the app.
*/
if (savedInstanceState == null)
{
if (isNetworkStatusAvailable(this))
{
TubeLineAsyncTask myLineTask = new TubeLineAsyncTask(this);
myLineTask.execute(NetworkUtils.buildLineUrl());
} else
{
Snackbar
.make(mCoordinatorLayout, "Please check your internet connection", Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new MyClickListener())
.show();
}
} else {
linesArrayList = savedInstanceState.getParcelableArrayList(KEY_LINES_LIST);
linesAdapter.setLinesList(linesArrayList);
}
getSupportLoaderManager().initLoader(FAVORITES_LOADER_ID, null, MainActivity.this);
favoritesAdapter = new FavoritesAdapter(this, MainActivity.this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs)
{
return new AsyncTaskLoader<Cursor>(this)
{
// Initialize a Cursor, this will hold all the task data
Cursor mFavoritesData = null;
// onStartLoading() is called when a loader first starts loading data
@Override
protected void onStartLoading()
{
if (mFavoritesData != null)
{
// Delivers any previously loaded data immediately
deliverResult(mFavoritesData);
}
else
{
// Force a new load
forceLoad();
}
}
// loadInBackground() performs asynchronous loading of data
@Override
public Cursor loadInBackground()
{
// Will implement to load data
// Query and load all task data in the background; sort by priority
// [Hint] use a try/catch block to catch any errors in loading data
try
{
return getContentResolver().query(TubeLineContract.TubeLineEntry.CONTENT_URI,
null,
null,
null,
TubeLineContract.TubeLineEntry.COLUMN_LINES_ID);
}
catch (Exception e)
{
Log.e(LOG_TAG, "Failed to asynchronously load data.");
e.printStackTrace();
return null;
}
}
// deliverResult sends the result of the load, a Cursor, to the registered listener
public void deliverResult(Cursor data)
{
mFavoritesData = data;
super.deliverResult(data);
}
};
}
/**
* Called when a previously created loader has finished its load.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
favoritesAdapter.swapCursor(data);
if (mPosition == RecyclerView.NO_POSITION) mPosition = 0;
mLineRecyclerView.smoothScrollToPosition(mPosition);
}
/**
* Called when a previously created loader is being reset, and thus
* making its data unavailable.
* onLoaderReset removes any references this activity had to the loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader)
{
favoritesAdapter.swapCursor(null);
}
ContentProvider delete method:
// Implement delete to delete a single row of data
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs)
{
// Get access to the database and write URI matching code to recognize a single item
final SQLiteDatabase db = mTubeLineDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
// Keep track of the number of deleted rows
int rowsDeleted; // starts as 0
//if (null == selection) selection = "1";
// Write the code to delete a single row of data
// [Hint] Use selections to delete an item by its row ID
switch (match)
{
// Handle the single item case, recognized by the ID included in the URI path
case LINE_WITH_ID:
// Get the line ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver of a change and return the number of items deleted
if (rowsDeleted != 0)
{
// A line was deleted, set notification
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of rows deleted
return rowsDeleted;
}
RecyclerViewAdapter:
public class FavoritesAdapter extends RecyclerView.Adapter<FavoritesAdapter.FavoritesAdapterViewHolder>
{
private static final String TAG = FavoritesAdapter.class.getSimpleName();
private Context context;
private Cursor cursor;
private LinesAdapter.LinesAdapterOnClickHandler mClickHandler;
public FavoritesAdapter(LinesAdapter.LinesAdapterOnClickHandler clickHandler, Context context)
{
mClickHandler = clickHandler;
this.context = context;
}
public class FavoritesAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@BindView(R.id.line_name)
TextView lineName;
public FavoritesAdapterViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
}
@Override
public void onClick(View v) {
cursor.moveToPosition(getAdapterPosition());
String lineName = cursor.getString(cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_NAME));
String lineId = cursor.getString(cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID));
Lines lines = new Lines(lineName, lineId);
mClickHandler.onClick(lines);
}
}
@Override
public void onBindViewHolder(FavoritesAdapter.FavoritesAdapterViewHolder holder, int position)
{
// get to the right location in the cursor
cursor.moveToPosition(position);
// Determine the values of the wanted data
int lineIdIndex = cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID);
int lineNameColumnIndex = cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_NAME);
final int id = cursor.getInt(lineIdIndex);
String stationName = cursor.getString(lineNameColumnIndex);
holder.itemView.setTag(id);
holder.lineName.setText(stationName);
Log.e(TAG, "Failed to load line text.");
}
@Override
public FavoritesAdapter.FavoritesAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
{
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.line_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new FavoritesAdapter.FavoritesAdapterViewHolder(view);
}
public Cursor swapCursor(Cursor c)
{
// check if this cursor is the same as the previous cursor (mCursor)
if (cursor == c)
{
return null; // bc nothing has changed
}
Cursor temp = cursor;
this.cursor = c; // new cursor value assigned
//check if this is a valid cursor, then update the cursor
if (c != null)
{
this.notifyDataSetChanged();
}
return temp;
}
@Override
public int getItemCount()
{
if (null == cursor)
return 0;
return cursor.getCount();
}
}
回答1:
Change
rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?", new String[]{id});
To
rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?", new String[]{String.valueOf(id)});
in ContentProvider delete method.
来源:https://stackoverflow.com/questions/54300848/deleting-a-single-sqlite-row-recyclerview-onswiped