Eliminare elemento da una ListView con SQlite

di il
7 risposte

Eliminare elemento da una ListView con SQlite

Buongiorno a tutti. Premetto che sono un principiante. All'interno di una classe DbHandler.java ho vari metodi, tra cui DeleteUser adibito all'eliminazione degli elementi sia dalla ListView sia dal Database.
 public void DeleteUser (int userid){
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(TABLE_Users, KEY_ID+" = ?",new String[]{String.valueOf(userid)});
        db.close();
    } 
Quindi tento di richiamarlo nella classe DetailsActivity in questo modo:
lv.setOnItemLongClickListener( new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick (AdapterView<?> parent, View view, int position, long id) {

                db.DeleteUser(position);

                return true;
            }
        } );
Questo però causa la chiusura forzata dell'app. Cosa sto sbagliando? Grazie

7 Risposte

  • Re: Eliminare elemento da una ListView con SQlite

    Probabilmente un'eccezione verrà sollevata per qualche ragione, causando il crash dell'app. Potresti postare lo stack trace dal LogCat?
  • Re: Eliminare elemento da una ListView con SQlite

    Grazie per la risposta. Il crash era dovuto ad un altro fattore apparentemente risolto. Ora semplicemente, dopo la pressione (diciamo 3 secondi), non accade nulla. L'elemento non viene cancellato e nel LogCat di conseguenza, non vedo comparire niente. Il metodo DeleteUser è stato prelevato da un file di esempio dal web, quindi ho dato per scontato fosse corretto. Più probabile stia sbagliando io la chiamata dello stesso (?)

    P.S.
    Se può essere d'aiuto, aggiungendo un Toast prima del comando return true
     Toast.makeText( DetailsActivity.this, "prova", Toast.LENGTH_SHORT ).show();
    in seguito alla pressione prolungata di uno degli elementi in ListView il text del Toast compare, quindi mi viene da pensare che il onItemLongClick funziona, ma il metodo di cancellazione non ne vuole sapere
  • Re: Eliminare elemento da una ListView con SQlite

    Presumo che il problema sia dovuto al fatto che la funzione deleteUser si aspetta in input l'ID della riga da eliminare, mentre nella callback passi "position", che è l'indice dell'elemento nella lista. Questi 2 numeri indicano cose diverse, per cui è normale che il funzionamento non corrisponda a quello atteso.

    Per sistemare il problema dovresti in qualche modo associare ad ogni elemento della lista il corrispondente ID proveniente dal DB. Un possibile modo per farlo è quello di usare il pattern ViewHolder. Non si tratta di una cosa particolarmente complicata da implementare, ma ci sono delle considerazioni di performance da considerare che, se trascurate, potrebbero portare a bug oscuri. Il modo più semplice per implementare ciò che chiedi penso che sia quello di migrare da una ListView a una RecyclerView, che integra nativamente questo pattern. Più info nella documentazione ufficiale: https://developer.android.com/guide/topics/ui/layout/recyclerview

    Un modo più semplice potrebbe essere quello di ottenere l'elemento corrispondente all'elemento grafico su cui fai il long click tramite il metodo "getItemAtPosition(position)" e di passare tale ID al metodo per cancellare l'utente.
  • Re: Eliminare elemento da una ListView con SQlite

    Grazie mille per aver dedicato tempo al mio problema e per la dettagliata risposta. Tenterò ovviamente in primis di percorrere la strada più breve, l'ultima da te citata e se non dovesse funzionare mi adopererò per riconvertire il tutto al RecyclerView. Per quanto riguarda il metodo getItemAtPosition , nel mio caso, dovrebbe proprio sostituire il DeleteUser o vanno applicati entrambi? Mi spiego meglio, una volta fatto questo
    lv.getItemAtPosition( position );
    come passo anche il metodo DeleteUser al db? Grazie
  • Re: Eliminare elemento da una ListView con SQlite

    In entrambi i casi dovresti comunque avere il metodo onItemLongClick perché è quello che viene chiamato dal sistema quando fai appunto un long click su un elemento. Al suo interno poi chiami getItemAtPosition che ti restituisce l'elemento cliccato. Nota non ti restituisce l'oggetto grafico (cioè la View) ma l'oggetto Java che hai usato per popolare la View - ed in questo caso è proprio ciò che ti serve perché è proprio esso che dovrebbe contenere quell'ID.

    Vorrei comunque precisare una cosa che non ho specificato prima per chiarire la differenza fra le 2 soluzioni proposte sopra: il pattern ViewHolder è vantaggioso SOLO se crei manualmente gli elementi grafici della lista (cioè se nel tuo adapter fai un override di getView in cui usi un inflater per creare la View). Altrimenti di fatto è inutile e anzi rischi di andare a introdurre bug
  • Re: Eliminare elemento da una ListView con SQlite

    Abbi pazienza di un povero principiante, ci sto provando ma c'è sempre qualcosa che non mi torna alla fine. Dunque questo è il MainActivity:
    public class MainActivity extends AppCompatActivity {
    
        EditText prodotto;
        Button btnAggiungi;
        Intent intent;
    
    
        @Override
        protected void onCreate (Bundle savedInstanceState) {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
           prodotto = (EditText)findViewById( R.id.editTxtProdotto );
    
            btnAggiungi = (Button)findViewById(R.id.btnAggiungi );
    
            btnAggiungi.setOnClickListener( new View.OnClickListener() {
                @Override
                public void onClick (View v) {
                    String prodottiStr = prodotto.getText().toString()+"\n";
                    DbHandler dbHandler = new DbHandler(MainActivity.this);
                    dbHandler.insertUserDetails(prodottiStr);
                    intent = new Intent(MainActivity.this,DetailsActivity.class);
                    startActivity(intent);
                    Toast.makeText(getApplicationContext(), "Prodotto Inserito Correttamente",Toast.LENGTH_SHORT).show();
    
                }
        } );
        }
        }
    
    L'oggetto Java di cui parli immagino sia "prodottiStr", ma trovandomi io all'interno di un altra classe (DetailsActivity), come faccio ad utilizzare l'oggetto all'interno di essa?

    P.S. Per una maggiore comprensione pubblico anche il resto della DetailsActivity:
    public class DetailsActivity extends AppCompatActivity {
        Intent intent;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView( R.layout.details);
    
            final DbHandler db = new DbHandler(this);
            final ArrayList<HashMap<String, String>> userList = db.GetUsers();
            final ListView lv = (ListView) findViewById(R.id.user_list);
            final ListAdapter adapter = new SimpleAdapter(DetailsActivity.this, userList, R.layout.list_row,new String[]{"prodotto"}, new int[]{R.id.prodottiStr});
            lv.setAdapter(adapter);
            Button back = (Button)findViewById(R.id.btnBack);
            back.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    intent = new Intent(DetailsActivity.this,MainActivity.class);
                    startActivity(intent);
                }
            });
    
           lv.setOnItemLongClickListener( new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick (AdapterView<?> parent, View view, int position, long id) {
    
                    //lv.getItemAtPosition( );
                    //db.DeleteUser
    
    Toast.makeText( DetailsActivity.this, "prova", Toast.LENGTH_SHORT ).show();
                    return true;
    
                }
           } );
        }
    }
  • Re: Eliminare elemento da una ListView con SQlite

    Non so come sia implementata la funzione GetUsers, ma presumo che tu restituisca una Map<String, String> che contenga dati tipo "prodotto" -> "nome prodotto", più eventualmente altre cose.
    Potresti aggiungere un'altra entry tipo "ID" -> "123456" (ovviamente il numero "123456" non puoi metterlo a caso ma deve provenire dal DB, quindi eventualmente dovrai aggiornare la query).

    In questo modo avendo ad esempio 2 prodotti, il metodo GetUser resituirà una lista così composta:
Devi accedere o registrarti per scrivere nel forum
7 risposte