Usuwanie pozycji z bazy poprzez kliknięcie na liście.

0

Witajcie,
Chcę poprzez dłuższe przytrzymanie na wybranej pozycji na liście, uruchomić menu po czym przy wyborze opcji Delete, wywołać metodę z klasy DatabaseHendler które usunie mi tą konkretną pozycję z bazy. Kod który napisałem teoretycznie powinien działać a mimo to działa źle. Złe działanie objawia się tym że usuwa mi zawsze pierwszą pozycję na liście a nie tą dla której rozwinąłem to menu i kliknąłem opcję delete. Tak to dokładnie wygląda:

 public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        switch (item.getItemId()) {
            case R.id.delete_id:
                TextView tv = (TextView) findViewById(R.id.playerNameListView);
                String n = tv.getText().toString();
                playerDb.deletePlayer(n);


        }
        return super.onContextItemSelected(item);
    }

Wydaje mi się że powinien pobrać mi wartość z pola textView z pozycji na której kliknąłem. Tymczasem pobiera mi wartość pierwszą na liście. Mogę Was poprosić o pomoc co robię źle?

0

Wywołujesz to na activity pewnie .ehhh stąd jakieś głupoty Ci się zwracają bo co ma Ci zwrócić jak ma całą listę tego?

W metodzie onCreateContextMenu wywołujesz przecież:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (v.getId() == R.id.lv) {
    ListView lv = (ListView) v;
    AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
    acmi.position//To jest zmienna którą musisz gdziesz przekazać
}

masz pozycję do której ustawiasz context menu to zapisz ją do jakiejś zmiennej będziesz wiedział co usuwać

pzdr

0

Właśnie ja odrobinę inaczej tworzę menu i może właśnie tu tkwi problem. Ja je buduję w taki sposób:

 @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_players_list_view, menu);
    }
0

@wojciechmaciejewski czy mogę Cię prosić o zerknięcie bo nie wiem gdzie tu popełniam błąd :(. Niby wydaje się być wszystko dobrze a jednak nie do końca ponieważ z bazy mi nic nie usuwa. Mam metodę w klasie DatabaseHelper:

public void deletePlayer(int id) {
        SQLiteDatabase db = this.getWritableDatabase();
        String sql = "DELETE FROM " + TABLE_NAME + " WHERE " + _id + " = " + id;
        db.execSQL(sql);
    }

Na wejściu spodziewa się int-a. Następnie tworzę menu:

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        itemPos = info.position; //to jest moja zmienna typu int
        if(itemPos != 0) {
            menu.add(0, v.getId(), 0, "Edit");
            menu.add(0, v.getId(), 0, "Delete");
        }
    }

I na końcu wywołanie:

@Override
    public boolean onContextItemSelected(MenuItem item) {
        if(item.getTitle() == "Delete") {
            playerDb.deletePlayer(itemPos);
        }
        return true;       
    }

Niby przekazuję pozycję a mimo to nie działa. Chyba że ja przekazuję tu pozycję z listy tzn element na liście ma pozycję 4 a w bazie ma 11. I może to tu jest problem. Tylko nie wiem jak pobrać pozycję która znajduje się w polu tekstowym bo defakto to właśnie w tym polu siedzi moje rzeczywiste ID elementu który chcę usunąć

---EDIT---
Zrobiłem to trochę na taką swoją logikę ale nie wiem czy moja logika jest słuszna dlatego jakbyś mógł rzucić okiem @wojciechmaciejewski to będę Ci ogromnie wdzięczny. Metody

onCreateContextMenu

nie zmieniałem. Przerobiłem natomiast klasę onContextItemSelected

 i wygląda ona teraz w taki sposób:

```java
public boolean onContextItemSelected(MenuItem item) {
        List<ValuesPlayers> allPlayers = playerDb.getAllPlayers();
        if(item.getTitle() == "Delete") {
            ValuesPlayers id = allPlayers.get(itemPos);
            int idPlayer = id.getId();
            playerDb.deletePlayer(idPlayer);
        }
        return true;
}

Pobrałem sobie z listy wartości z określonej pozycji a następnie wybrałem wartość która mnie interesuje czyli ID gracza które zapisane jest w bazie. Czy jest to dobrze? Działać działa.

0

Kasujesz playera z Id takim jaki numer na liście wybrałeś...... To chyba nie jest to o co Ci chodzi, bo możesz mieć na pierwszym mijesu listy playera z ID 100 a skasujesz tego z id = 0. To chyba źle co?

W adapterze masz na pewno listę obiektów które wyświetlasz nie? Player Student czy jak tam zwał. Ten obiekt ma pole id z tego co pamiętam z innego wątku.

Także to co musisz zapamiętać to nie item.position musisz wziąć adapter.getObjectsAtPosition(item.position).getId czy coś w tym stylu....

0

@wojciechmaciejewski dzięki za cierpliwość do mnie. Naprawdę to doceniam. Przepraszam że drążę temat ale nie wystarczy mi że coś działa. Chcę się nauczyć naprawdę dobrze programować i robić to porządnie a nie byle jak, byle by działało. Powiem Ci jak działa obecnie mój kod.

Po wyborze "Delete" z menu, wywoływana jest metoda z klasy DatabaseHelperPlayers która na wejściu dostaje int-a i tym int-em jest ID pobrane z TextView z pozycji w którą kliknąłem. To ID to nie jest pozycja gracza na mojej liście tylko ID jakie on ma w bazie. I po tym ID wywoływana jest metoda delete po czym lista jest odświeżana, czyli wykonuje się kolejny select.

Tylko coś kurcze robię źle. Działać działa ale to nie może tak być. Jest do niczego :(:(:(:(. Pokażę co robię, jeśli będziesz miał chwilkę na zwrócenie mi uwagi gdzie robię błąd to było by super. Mam nadzieję że inni koledzy też pomogą. Nie czekam na gotowe rozwiązanie tylko jak widzicie sam też próbuję i staram się ogarnąć jak najwięcej.

Na początku dwie klasy, pierwsza z BaseAdapterem:

public class PlayerBaseAdapter extends BaseAdapter {
    private List<ValuesPlayers> valuesPlayers;
    private Context context;
    private LayoutInflater inflater;

    public PlayerBaseAdapter(List<ValuesPlayers> valuesPlayers, Context context) {
        this.valuesPlayers = valuesPlayers;
        this.context = context;

    }
    @Override
    public int getCount() {
        return valuesPlayers.size();
    }

    @Override
    public Object getItem(int position) {
        return valuesPlayers.get(position);
    }

    @Override
    public long getItemId(int position) {
        return valuesPlayers.get(position).getId();
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;

        if(view == null) {
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.row_players, null);
        }

        ValuesPlayers player = this.valuesPlayers.get(position);
        TextView id = (TextView) view.findViewById(R.id.id);
        TextView playerNameListView = (TextView) view.findViewById(R.id.playerNameListView);

        id.setText(String.valueOf(player.getId()));
        playerNameListView.setText(player.getNamePlayer());

        return view;

    }




    static class ViewHolder {
        TextView idPlayer, namePlayer;
    }

}

następnie tzw klasa "entity":

public class ValuesPlayers {
    private int id;
    private String namePlayer;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNamePlayer() {
        return namePlayer;
    }

    public void setNamePlayer(String namePlayer) {
        this.namePlayer = namePlayer;
    }
}

oraz mój select z klasy DatabaseHelperPlayers:

public List<ValuesPlayers> getAllPlayers() {
        List<ValuesPlayers> playerList = new ArrayList<ValuesPlayers>();
        SQLiteDatabase db = this.getReadableDatabase();
        String sqlSelect = "SELECT " + _id + ", " +
                columnPlayerName  + " FROM " + TABLE_NAME;
        Cursor select = db.rawQuery(sqlSelect, null);


        if(select.moveToFirst()) {
            do {
                ValuesPlayers player = new ValuesPlayers();
                player.setId(Integer.parseInt(select.getString(0)));
                player.setNamePlayer(select.getString(1));
                playerList.add(player);
            }
            while(select.moveToNext());
        }
        return playerList;
    }

Dalej tworzę klasę do zarządzania graczami. Początek:

public class ManagePlayers extends AppCompatActivity {
    DatabaseHelperPlayer playerDb = new DatabaseHelperPlayer(this);
    ListView playersList;
    int itemPos;

Teraz buduję metodę która wyświetli mi moją listę i tu chyba jest źle ponieważ tworzę listę pod którą którą przypisuję metodę getAllPlayers a klasy z bazą i na jej postawię buduję adapter:

private void playersListView() {
        List<ValuesPlayers> allPlayers = playerDb.getAllPlayers();
        playersList = (ListView) findViewById(R.id.listPlayer);
        PlayerBaseAdapter adt = new PlayerBaseAdapter(allPlayers, getApplicationContext());
        playersList.setAdapter(adt);
    }

Następnie tworzę sobie menu kontekstowe gdzie do wcześniej zadeklarowanej zmiennej itemPos przypisuję pozycję elementu na który kliknięto:

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        itemPos = info.position;
            menu.add(0, v.getId(), 0, "Edit");
            menu.add(0, v.getId(), 0, "Delete");

    }

Na końcu tworzę metodę onContextItemSeleceted w której ponownie buduję listę do której przypisuję metodę pobierającą graczy z bazy z klasy do obsługi bazy a następnie pobieram ID z pozycji na którą kliknięto i daje je jako parametr dla metody deletePlayer:

@Override
     public boolean onContextItemSelected(MenuItem item) {
        List<ValuesPlayers> allPlayers = playerDb.getAllPlayers();
        if(item.getTitle() == "Delete") {
            ValuesPlayers id = allPlayers.get(itemPos);
            int idPlayer = id.getId();
            playerDb.deletePlayer(idPlayer);
            playersListView();
        }
        return true;

    }

Nie jest to dobrze. Świadczy o tym choćby to że w dwóch metodach tworzę tą samą listę. Ale nie wiem jak zrobić to prawidłowo :(:(.

1

Dobrze przynajmniej że sam wiesz że jest do d**y :P

Po cholerę pobierasz znów z bazy danych listę przy kasowaniu skoro masz już tą listę w adapterze? Zrób w adapterze metodę deleteAtPosition która będzie usuwała wybraną pozycję z listy i używała magicznej metody notifyDataSetChange() http://developer.android.com/reference/android/widget/BaseAdapter.html#notifyDataSetChanged()

żeby zaktalizować widok na liście nie bez sesnu ładujesz wszystko od nowa. Usuwasz z bazy tak jak usuwasz i wsio

0

Ale to sugerujesz aby zrobić dwa kasowania, pierwsze kasowanie usuwa mi element z listy a drugie usuwa element z bazy?

Ok, metoda notifyDataSetChanged () odświeży mi moją listę ale tak czy inaczej muszę ten element usunąć też z bazy bo gdy uruchamiam activity to pobierana jest na starcie lista graczy. Jeśli będę usuwał ich tylko z listy to przy ponownym uruchomieniu oni nadal na niej będą bo się pobiorą. Mi się zdecydowanie nie podoba sposób w jaki pobieram ID gracza którego chcę usunąć. To jest do d**y. Tworzenie 2 razy tej samej listy w dwóch różnych metodach jest już do niczego. Próbuję dojść jak zrobić to prawidłowo. Nie ta żeby tylko działało ale żeby działało i było logiczne i sensowne.

0

A czemu do wyświetlania listy nie użyjesz http://developer.android.com/reference/android/widget/CursorAdapter.html? Usuniesz coś z bazy, cursor.requery(), notifyDataSetChanged() i szafa gra.

0

Słuchajcie, przerobiłem sobie swój BaseAdapter tak aby korzystał z ViewHolder i nie umiem zrozumieć jednej rzeczy. Proszę, wytłumaczcie mi to jeśli to nie problem. Więc od początku, mam metodę w klasie DatabaseHelper pobierającą dane z bazy:

public ArrayList<ValuesPlayers> getAllPlayers() {
        ArrayList<ValuesPlayers> playerList = new ArrayList<ValuesPlayers>();
        SQLiteDatabase db = this.getReadableDatabase();
        String sqlSelect = "SELECT " + _id + ", " +
                columnPlayerName  + " FROM " + TABLE_NAME;
        Cursor select = db.rawQuery(sqlSelect, null);


        if(select.moveToFirst()) {
            do {
                ValuesPlayers player = new ValuesPlayers();
                player.setId(Integer.parseInt(select.getString(0)));
                player.setNamePlayer(select.getString(1));
                playerList.add(player);
            }
            while(select.moveToNext());
        }
        return playerList;
    }

Klasę ValuesPlayers:

public class ValuesPlayers {
    private int id;
    private String namePlayer;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNamePlayer() {
        return namePlayer;
    }

    public void setNamePlayer(String namePlayer) {
        this.namePlayer = namePlayer;
    }
}

Klasę BaseAdapter:

public class PlayerBaseAdapter extends BaseAdapter {
    private ArrayList<ValuesPlayers> valuesPlayers = new ArrayList<ValuesPlayers>();
    private Context context;
    private LayoutInflater inflater;

    public PlayerBaseAdapter(ArrayList<ValuesPlayers> valuesPlayers, Context context) {
        this.valuesPlayers = valuesPlayers;
        this.context = context;
        inflater = LayoutInflater.from(this.context);

    }
    @Override
    public int getCount() {
        return valuesPlayers.size();
    }

    @Override
    public Object getItem(int position) {
        return valuesPlayers.get(position);
    }

    @Override
    public long getItemId(int position) {
        return valuesPlayers.get(position).getId();
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        ViewHolder holder;

        if(view == null) {
            view = inflater.inflate(R.layout.row_players, null);
            holder = new ViewHolder();
            view.setTag(holder);
        }
        else {
            holder = (ViewHolder) view.getTag();
        }
        holder.idPlayer = detail(view, R.id.id, String.valueOf(valuesPlayers.get(position).getId()));
        holder.namePlayer = detail(view, R.id.playerNameListView, valuesPlayers.get(position).getNamePlayer());

        return view;

    }

    private TextView detail(View v, int resId, String text) {
        TextView tv = (TextView) v.findViewById(resId);
        tv.setText(text);
        return tv;
    }

    static class ViewHolder {
        TextView idPlayer, namePlayer;
    }

}

I swoją aktywność. Chcę użyć zwartości swojej listy w kilku metodach ale nie mogę. Gdy zrobię coś takiego:

public class ManagePlayers extends AppCompatActivity {
    DatabaseHelperPlayer playerDb = new DatabaseHelperPlayer(this);
    ListView playersList;
    int itemPos;
    ArrayList<ValuesPlayers> listPlayer = new ArrayList<ValuesPlayers>();  //<----------------------------

czyli zainicjuję listę tu gdzie zaznaczyłem strzałką a następnie ją próbuję ją wyświetlić:

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

            PlayerBaseAdapter adt = new PlayerBaseAdapter((ArrayList<ValuesPlayers>) listPlayer, this);
            playersList.setAdapter(adt);
            registerForContextMenu(playersList);

lista jest pusta. Nie pobiera się nic. Dopiero gdy zrobię tak:

public class ManagePlayers extends AppCompatActivity {
    DatabaseHelperPlayer playerDb = new DatabaseHelperPlayer(this);
    ListView playersList;
    int itemPos;
...
...
        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_manage_players);

            ArrayList<ValuesPlayers> listPlayer = playerDb.getAllPlayers();
            PlayerBaseAdapter adt = new PlayerBaseAdapter((ArrayList<ValuesPlayers>) listPlayer, this);
            playersList.setAdapter(adt);
            registerForContextMenu(playersList);

to dopiero zaczyna działać. Ale przy takim układzie gdy chcę użyć listy listPlayer w innej metodzie to muszę w niej ponownie robić: ArrayList<ValuesPlayers> listPlayer = playerDb.getAllPlayers(); a to chyba nie jest prawidłowe. Nie można tej listy zainicjować w taki sposób abym robiąc to raz, mógł się do niej odwoływać w kilku metodach?

0

Połącz jeden kod z drugim, trzymaj listę jako pole klasy a w onCreate przypisz do niej wartosci z playerDb.getAllPlayers().

1 użytkowników online, w tym zalogowanych: 0, gości: 1