如何同时从recyclerView和sqlite数据库中删除行?

问题描述:

我正在使用回收者视图和SQLite数据库创建一个应用程序.当用户输入一些数据时,它会显示在回收者"视图中,并且还会添加到我的数据库中.现在,我想在回收者视图中实现delete功能.

I'm creating an app with recycler view and SQLite database. When user enters some data, it is displayed in recycler view and also added to my database. Now I want to implement delete functionality in recycler view.

我想要的东西:

我想同时从数据库和回收者视图中删除所需的行,而不会得到任何意外结果.并且所有行均应删除.

I want to delete the required row from database and also from recycler view at the same time, without getting any unexpected results. And all the rows should be deleted.

我尝试过的事情:

我已经在回收站视图的cardView上实现了onLongClickListener(我使用cardView作为回收站视图的行).现在,当使用它的长按时,我将获得适配器位置.并删除该位置的数据库条目.

I've implemented onLongClickListener on cardView of recycler view (I'm using cardView as the row of recycler view). now when use long clicks its, I'm getting adapter position. and delete the entry of database at that position.

但是,这给了我意外的结果,例如:再次创建回收器视图的活动时,所有在实际删除行下面的删除行或一次删除的行都会再次出现,并且永远不会删除最后2-3行,数据库条目已被删除.

But this gives me unexpected results like: All the rows deleted which are below the actual deleting row or the row which are deleted once appears back when the activity of recycler view is again created and never deleting last 2-3 rows, which database entries are deleted already.

我的回收站视图适配器代码是:

My code of adapter of recycler view is:

public class AdapterForMain extends RecyclerView.Adapter<AdapterForMain.ViewHolder>{
ArrayList<String> mDataset;
ArrayList<String> mfooterSet;

private int[] icon;
MainActivity context;
DatabaseHelper myDb;


public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    // each data item is just a string in this case

    public TextView txtHeader;
    public TextView txtFooter;
    public ImageView imgView;
 //   MainActivity mainActivity;

    CardView cardView;

    public ViewHolder(View v) {
        super(v);
        txtHeader = (TextView) v.findViewById(R.id.firstLine);
        txtFooter = (TextView) v.findViewById(R.id.secondLine);
        imgView = (ImageView) v.findViewById(R.id.icon);

        cardView = (CardView)v.findViewById(R.id.cardView);
        cardView.setOnClickListener(this);
        cardView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                myDb = new DatabaseHelper(context);

                int detingPos = getAdapterPosition();
                boolean isDeleted = myDb.deleteEntry(detingPos);

                if(isDeleted){
                    mDataset.remove(getAdapterPosition());
                    notifyItemRemoved(getAdapterPosition());
                    notifyItemRangeChanged(getAdapterPosition(),mDataset.size());

                }
                Toast.makeText(context,"Delete from here",Toast.LENGTH_SHORT).show();

                  return true;
            }
        });
    }

    @Override
    public void onClick(View view) {

       // Toast.makeText(context,Integer.toString(getAdapterPosition()),Toast.LENGTH_SHORT).show();
        context.detailActivity(getAdapterPosition(),mDataset.get(getAdapterPosition()),mfooterSet.get(getAdapterPosition()));
    }
}


// Provide a suitable constructor (depends on the kind of dataset)
public AdapterForMain(ArrayList<String> myDataset, ArrayList<String> myFooterSet, int[] images, MainActivity context0) {
    icon = images;
    mDataset = myDataset;
    mfooterSet = myFooterSet;
    context = context0;
}

// Create new views (invoked by the layout manager)
@Override
public AdapterForMain.ViewHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {
    // create a new view
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_main, parent, false);
    // set the view's size, margins, paddings and layout parameters
    ViewHolder vh = new ViewHolder(v);

    return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    final String name = mDataset.get(position);
    holder.txtHeader.setText(mDataset.get(position));
    holder.txtHeader.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            //  Toast.makeText(AdapterForMain.this,"Settings Activity is under Construction.",Toast.LENGTH_SHORT).show();
        }
    });

    holder.txtFooter.setText(mfooterSet.get(position));
    holder.imgView.setImageResource(icon[position%1]);
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    return mDataset.size();
}}

delete方法的代码:

    public boolean deleteEntry(int row) {
        SQLiteDatabase db=this.getWritableDatabase();
        db.delete(TABLE_NAME, COL_1 + "=" + row,null);
        return true;
    }

我已经看到了以下链接的解决方案,但无法获得我想要的确切解决方案.

I've seen the following link for the solution but can't get exact solution for what I want.

链接1
>链接2 >

Link 1
Link 2

首先,您需要将long传递给您的删除方法,而传递给int.其次,您应该将确切的rowId 传递给您的方法,而不是适配器位置.因为适配器位置始终是从0到某个数字之间的连续数字集,之间没有间隙,所以在数据库中,从表中删除数据后,某些数字将不用于rowId.例如,如果删除第5行,则SQLite db不再使用索引4.您将拥有0、1、2、3、5、6 ...这样的行,因为它是自动递增的.

First of all you need to pass long to your delete method and not int. Secondly, your should pass the exact rowId to your method and not the adapter position. Because adapter position will always be continuous set of numbers from 0 to some number without gaps between, while in your database you will have some numbers not used for rowId after deletion of data from table. For example, if you delete the 5th row then index 4 is not used any more by SQLite db. Your will have rows like 0, 1, 2, 3, 5, 6... Because it is autoincrement.

我建议您将数据存储在二维数组或ArrayList中.然后,从db检索数据时,也需要将COL_1的值传递给相应的文本.这样,您将始终知道哪个行号包含特定数据,并在要删除该行号时显示该行号.

I will advice you to store your data in two dimensional array or ArrayList. Then you need to pass values of COL_1 too with the corresponding text when retreiving data from db. That way you will be always aware of which row number contains particular data and show that row number when you want to delete it.

因为只有一列数据,所以很容易为您显示带有二维数组的版本.

Because you have only one column for data, it will be easy to show you the version with two dimensional array.

您可以把它想象成一个数组数组:

You can imagine it as array of arrays:

mDataset->

mDataset ->

位置:
0 | array1
1 | arrays2
2 | array3

... | ...

at positions:
0 | array1
1 | arrays2
2 | array3

... | ...

array1->

位置:
0 | rowId
1 | textData

at positions:
0 | rowId
1 | textData

array2->

位置:
0 | rowId
1 | textData

at positions:
0 | rowId
1 | textData

,依此类推.但是您将需要更改从db检索数据的方法的代码,以便它将返回上述ArrayList.

and so on. But you will need to change the code of method for retreiving data from db so that it will return the above mentioned ArrayList.

代码如下所示:

在您的数据库中:

// getData method
public ArrayList<ArrayList<String>> getData() {
    SQLiteDatabase db=this.getWritableDatabase();
    String[] columns = new String[]{COL_1, COL_2};
    Cursor c = ourDatabase.query(TABLE_NAME, columns, null, null, null, null, null);

    int rowId = c.getColumnIndex(COL_1);
    int text = c.getColumnIndex(COL_2);

    ArrayList<ArrayList<String>> data = new ArrayList<ArrayList<String>>();

    for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
        ArrayList<String> temp = new ArrayList<String>();
        temp.add(c.getString(rowId));
        temp.add(c.getString(text));
        data.add(temp);
    }

    return data;
}

// deleteEntry method
public boolean deleteEntry(long row) {
    SQLiteDatabase db=this.getWritableDatabase();
    db.delete(TABLE_NAME, COL_1 + "=" + row, null);
    return true;
}

数据集:

ArrayList<ArrayList<String>> mDataSet = //initialize or pass data

然后将其用作:

int position = mDataset.get(getAdapterPosition).get(0);
boolean isDeleted = myDb.deleteEntry(Long.parseLong(position));

long position = mDataset.get(getAdapterPosition).get(0);
boolean isDeleted = myDb.deleteEntry(position);