【问题标题】:Deleting item from ListView and Database with OnItemClickListener使用 OnItemClickListener 从 ListView 和数据库中删除项目
【发布时间】:2018-11-19 08:55:19
【问题描述】:

我创建了一个数据库并设法将添加的项目显示到 ListView 中。现在我需要一种从 ListView 和数据库中删除项目的方法。

public class ZeigeFaecherListe extends AppCompatActivity {

    DatabaseHelper myDb;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.zeige_faecher);

        myDb = new DatabaseHelper(this);
        ListView listViewFaecher = (ListView) findViewById(R.id.listViewFaecher);

        final ArrayList<String> faecherListe = new ArrayList<>();
        Cursor res = myDb.zeigeFaecher();

        if (res.getCount() == 0){
            Toast.makeText(ZeigeFaecherListe.this, "Keine Fächer gefunden", Toast.LENGTH_LONG).show();
        } else {
            while (res.moveToNext()){
                faecherListe.add(res.getString(1));
                ListAdapter fachListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, faecherListe);
                listViewFaecher.setAdapter(fachListAdapter);
            }
        }

        listViewFaecher.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

            }
        });
    }
}

【问题讨论】:

  • 没有。您需要一种方法从数据库中删除项目,然后相应地更新 ListView。
  • 是的,但我需要一种方法来使用列表视图选择项目,但我不知道如何实现。
  • 查看传递给onItemClick方法的最后一个参数
  • 你有 id 参数,它就是为此而存在的。
  • 用户如何删除一个项目?只需点击它?还是他们必须选择它然后按下删除按钮?

标签: android sqlite listview android-sqlite


【解决方案1】:
listViewFaecher.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

         // Call delete method here by passing position
         //position will contain the position of item clicked by the user.
     }
});

【讨论】:

    【解决方案2】:

    简而言之,您需要能够通过 ListView 可用的数据来区分要删除的行。如果从游标中检索到的值作为第二列(即使用res.getString(1)) 提取的字符串,并且该值将是唯一的,则可以检索它并将其用于删除。

    但是,有一些问题,使用ListAdapter 可能还不够。还有其他适配器,例如提供更多功能的 ArrayAdapter 和重要的 notifyDatasetChanged 方法(将刷新关联的 ListView)。

    为光标的每次迭代创建一个新的适配器是一种浪费。所以适配器应该在循环之外创建一次。

    我建议删除项目点击太容易意外点击,删除项目 LongClick 将不太容易意外删除。

    如果将变量移动为类变量,则不必将它们声明为 final。

    因此,根据上述情况,您可以:-

    数组适配器方法

    public class ZeigeFaecherListe extends AppCompatActivity {
    
        DatabaseHelper myDb;
        Cursor res;
        ListView listViewFaecher;
        ArrayAdapter<String> fachListAdapter;
        ArrayList<String> faecherListe;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.zeige_faecher);
    
            listViewFaecher = (ListView) this.findViewById(R.id.listview);
            myDb = new DatabaseHelper(this);
            addSomeData(); //<<<<<<<<<< ADDED for testing
    
            faecherListe = new ArrayList<>();
            res = myDb.zeigeFaecher();
            while (res.moveToNext()) {
                faecherListe.add(res.getString(1));
            }
    
            //<<<< NOTE outside of the loop as this only needs to be done once
            fachListAdapter = new ArrayAdapter<String>(
                    this,
                    android.R.layout.simple_list_item_1,
                    faecherListe
            );
            listViewFaecher.setAdapter(fachListAdapter);
    
            //<<<<< NOTE used LONG CLICK listener (less likely to accidentally delete)
            listViewFaecher.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                    myDb.deleteRow((String)fachListAdapter.getItem(position));
                    faecherListe.remove(position);
                    fachListAdapter.notifyDataSetChanged(); 
                    return true; //<<<< Indicate that this longclick has been used
                }
            });
        }
    
        private void addSomeData() {
            for (int i=1; i <= 10; i++) {
                myDb.addRow("Row " + String.valueOf(i));
            }
        }
    }
    

    除了上面的 deletRow 方法是:-

    public int deleteRow(String col2) {
        SQLiteDatabase db = this.getWritableDatabase();
        return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
    }
    
    • 在哪里
      • TB001 是设置为表名的常量字符串。
      • COL_TB001_DATA 是第 2 列的列名。

    警告上述解决方案只有在第二列包含唯一数据时才能正常工作,否则会删除多行。

    还有一个假设是删除有效,最好有:-

            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (myDb.deleteRow((String)fachListAdapter.getItem(position))<0) {
                    faecherListe.remove(position);
                }
                fachListAdapter.notifyDataSetChanged(); 
                return true; //<<<< Indicate that this longclick has been used
            }
    

    光标适配器方法

    但是,还有其他适合游标的适配器可以消除对中间数组的需求。您可以使用 CursorAdapter。对于 CursorAdapter,列名 _id 是必需的,并且该列应该是 long 并且还可以唯一标识行。其意图和名称是使用 rowid 的别名(这也是 CONSTANT BaseColumns._ID 存在的原因)。

    rowid 的别名是通过定义?? INTEGER PRIMARY KEY 来创建的?是列名。因此,理想情况下,表的定义应该包括带有_id INTEGER PRIMARY KEY 的列定义,例如CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT) (你可以在 INTEGER PRIMARY KEY 后面加上关键字 AUTOINCREMENT,但通常你不会这样做,因为它有开销 SQLite Autoincrement

    如果您的表没有这样的列,那么您可以在查询数据时始终在游标中创建一列,使用 rowid AS _id 例如如果您的 SQL 等于 SELECT * FROM mytable,那么您可以使用 SELECT *, rowid AS _id FROM mytable

    在本例中,将使用股票 SimpleCursorAdapter,代码可以是:-

    public class ZeigeFaecherListe extends AppCompatActivity {
    
        DatabaseHelper myDb;
        Cursor res;
        ListView listViewFaecher;
        SimpleCursorAdapter fachSimpleCursorAdapter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.zeige_faecher);
    
            listViewFaecher = (ListView) this.findViewById(R.id.listview);
            myDb = new DatabaseHelper(this);
            addSomeData(); //<<<<<<<<<< ADDED for testing
    
            faecherListe = new ArrayList<>();
            res = myDb.zeigeFaecher();
            fachSimpleCursorAdapter = new SimpleCursorAdapter(this,
                    android.R.layout.simple_list_item_1, //<<<< The layout
                    res, //<<<< The Cursor
                    new String[]{"_data"}, //<<<< The column names from which to get the data
                    new int[]{android.R.id.text1} //<<<< The ids of the views in which the data is placed
                    );
            listViewFaecher.setAdapter(fachSimpleCursorAdapter);
            listViewFaecher.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                    // id is the value of the respective _id column
                    //<<<< Normally you would have the delete method in the Databasehelper >>>>
                    myDb.getWritableDatabase().delete("mytable","_id=?",new String[]{String.valueOf(id)});
                    fachSimpleCursorAdapter.swapCursor(myDb.zeigeFaecher()); // Tell the adapter about the new cursor
                    return true;
                }
            });
        }
    }
    

    注意,因为 _id 列将始终是唯一的,如果显示的值不唯一,此方法只会删除特定行而不是多行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多