【问题标题】:How to delete rows from recyclerView and sqlite database both?如何从 recyclerView 和 sqlite 数据库中删除行?
【发布时间】:2016-10-05 07:52:06
【问题描述】:

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

我想要什么:

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

我的尝试:

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

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

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

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

【问题讨论】:

  • 删除后你必须重新加载适配器到recyclerview
  • 使用this适配器
  • @pskink 我不想使用自定义适配器。
  • @kgandroid 但是如何重新加载呢?那么上面提到的其他一些意想不到的结果呢?
  • 现在您正在使用 custom 适配器,我发布的是通用的Cursor 适配器

标签: java android database sqlite android-recyclerview


【解决方案1】:

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

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

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

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

mDataset ->

位置:
0 |数组1
1 |数组2
2 |数组3

... | ...

array1 ->

位置:
0 |行号
1 |文本数据

array2 ->

位置:
0 |行号
1 |文本数据

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

【讨论】:

  • 好的,我明白我的逻辑有什么问题。但是我的代码的变化是:int position = mDataset.get(getAdapterPosition).getRowId();
  • 我无法理解.getRowID() 部分。
  • 您可以通过使用this 通用Cursor 适配器轻松做到这一点,而不是使用two dimensional array or ArrayList.
  • @pskink 你是 ri8,我们可以使用通用游标适配器轻松做到这一点,但为此我必须更改我的整个代码。而且我的错误可能太多。
  • 好的,首先,您正在复制数据:这是存储所有数据的Cursor,那么在您的ArrayList 中复制它的原因是什么(我指出的适配器只是使用Cursor 来提供数据),而且您正在复制整个数据集,这可能导致OOM 错误(您正在浪费内存和CPU 时间),请注意SQLiteCursor 扩展了AbstractWindowedCursor,它将数据存储在一个小的CursorWindow 从而允许处理甚至巨大的数据集,第三,您已经注意到内部ArrayList 仅存储两个Strings 效率极低
【解决方案2】:

通过行 id 从 Sqlite 中删除对象

// Deleting single contact  
    public void deleteContact(Contact contact) {  
        SQLiteDatabase db = this.getWritableDatabase();  
        db.delete(TABLE_CONTACTS, KEY_ID + " = ?",  
                new String[] { String.valueOf(contact.getID()) });  
        db.close();  
    } 
Deleting object from RecyclerView:

RecyclerView recyclerView= (RecyclerView) view.findViewById(R.id.recyclerView);

    LinearLayoutManager layoutManager=new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
    recyclerView.setLayoutManager(layoutManager);
    parseArgument();

    adapter=new ReviewRecyclerAdapter(reviewArrayList);
    recyclerView.setAdapter(adapter);
    recyclerView.setHasFixedSize(false);
    reviewArrayList.remove(contact);//pass contact you want to delete
    adapter.notifyDataSetChanged();

【讨论】:

    猜你喜欢
    • 2019-05-16
    • 2023-01-13
    • 2021-10-27
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    相关资源
    最近更新 更多