删除单个 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 如何更新本地数据库中的单个记录

sqlite 通过多于两行删除行组

使用 SQLite 的搜索结果更新 RecyclerView

从表视图中删除行并从 sqlite 数据库中删除记录

SQLite 删除特定行不起作用

上传到服务器后删除 SQLite 数据行?