java - 如何从 recyclerView 和 sqlite 数据库中删除行?

标签 java android database sqlite android-recyclerview

我正在创建一个带有回收器 View 和 SQLite 数据库的应用程序。当用户输入一些数据时,它会显示在回收器 View 中,并且也会添加到我的数据库中。现在我想在回收器 View 中实现删除功能。

我想要什么:

我想同时从数据库和回收器 View 中删除所需的行,而不会得到任何意外的结果。并且所有行都应该被删除。

我尝试过的:

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.

但这给了我意想不到的结果,例如:当再次创建回收器 View 的 Activity 时,实际删除行下方的所有已删除行或已删除的行都会出现,并且不会删除最后 2-3 行,这数据库条目已被删除。

我的回收器 View 适配器代码是:

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;
    }

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

Link 1
Link 2

最佳答案

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

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

因为你只有一列数据,所以很容易向你展示二维数组的版本。

你可以把它想象成数组的数组:

mDataset ->

职位:
<强>0 |数组1
1 |数组2
2 |数组3
... | ...

数组1 ->

职位:
<强>0 | rowId
1 |文本数据

数组2 ->

职位:
<强>0 | rowId
1 |文本数据

等等。但是您需要更改从数据库检索数据的方法的代码,以便它将返回上面提到的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);

关于java - 如何从 recyclerView 和 sqlite 数据库中删除行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39868291/

相关文章:

java - 为外部库的类提供前缀

Javascript 数组不会在 componentDidMount 之外更新

java - 在java程序中加载属性

java - ActiveMQ ObjectMessage 安全性不适用于带有 SERIALIZABLE_PACKAGES 变量的 Linux

java - LayoutInflater 膨胀 fragment

Android:是否可以仅针对联系人同步阻止谷歌同步服务?

c# - 在实体中正确创建导航类

c# - Nhibernate 和枚举

java - Kerberos:从 key 表文件javax.security.auth.login.Login.log <user>的登录失败:无法从用户获取p密码

android - Eclipse 说我的 SDK 工具已经过时了