删除单个 SQlite 行 RecyclerView onSwiped
Posted
技术标签:
【中文标题】删除单个 SQlite 行 RecyclerView onSwiped【英文标题】:Deleting a single SQlite row RecyclerView onSwiped 【发布时间】:2019-06-15 11:38:53 【问题描述】:我将文本项存储在 RecyclerView 适配器和内容提供程序中。该列表可从菜单选项访问。通过滑动删除项目。目前,项目正在保存,但未删除。我已经调试过,它显示“id”为 0(未在 Main Activity 中检索):
int id = (int) viewHolder.itemView.getTag();
所选项目未从屏幕上滑出。我的代码基于这个结构:
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
我查看了这个帖子和帖子中的链接帖子,我的代码应该可以工作。它以前在另一个项目中工作过。收藏夹适配器类中的光标有问题吗?提前谢谢你。
Swipe to Dismiss for RecyclerView
还有这个帖子:
Deleting Row in SQLite in Android
Main Activity 中的 onSwiped 和 Loader Cursor 方法:
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 删除方法:
// 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】:改变
rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?", new String[]id);
到
rowsDeleted = db.delete(TubeLineContract.TubeLineEntry.TABLE_NAME, "id=?", new String[]String.valueOf(id));
在ContentProvider删除方法中。
【讨论】:
已解决。 id 有错别字。 “id”是一个字符串,而不是一个 int。以上是关于删除单个 SQlite 行 RecyclerView onSwiped的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin.Forms 中的 sqlite 如何更新本地数据库中的单个记录