Autore Topic: Problema selezione di checkbox in una lista  (Letto 1738 volte)

Offline andream1977

  • Utente normale
  • ***
  • Post: 260
  • Respect: +7
    • Mostra profilo
  • Dispositivo Android:
    Nexus S
  • Sistema operativo:
    windows xp
Problema selezione di checkbox in una lista
« il: 02 Marzo 2011, 17:34:11 CET »
0
Ho una lista dove in ogni riga c'è un checkbox
Se clicco su un checkbox, automaticamente ne seleziona anche un altro nella lista (ad esempio seleziono il secondo mi seleziona anche il terz'ultimo)
Sapete dirmi come mai?
Questo è il mio codice:

Phone.java
Codice (Java): [Seleziona]
public class Phone extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.phone_main);
       
        ListView list = (ListView)findViewById(R.id.ListView01);
       
        List<Phonebook> listOfPhonebook = new ArrayList<Phonebook>();
        listOfPhonebook.add(new Phonebook("Test","9981728","test@test.com"));
        listOfPhonebook.add(new Phonebook("Test1","1234455","test1@test.com"));
        listOfPhonebook.add(new Phonebook("Test2","00000","test2@test.com"));
       
        listOfPhonebook.add(new Phonebook("Test3","4","test3@test.com"));
        listOfPhonebook.add(new Phonebook("Test4","5","test41@test.com"));
        listOfPhonebook.add(new Phonebook("Test5","6","test5@test.com"));
       
        listOfPhonebook.add(new Phonebook("Test6","7","test6@test.com"));
        listOfPhonebook.add(new Phonebook("Test7","8","test71@test.com"));
        listOfPhonebook.add(new Phonebook("Test8","9","test8@test.com"));
       
        listOfPhonebook.add(new Phonebook("Test9","10","test9@test.com"));
        listOfPhonebook.add(new Phonebook("Test10","11","test10@test.com"));
        listOfPhonebook.add(new Phonebook("Test11","12","test11@test.com"));
        PhonebookAdapter adapter = new PhonebookAdapter(this, listOfPhonebook);
       
        list.setAdapter(adapter);
    }
}

PhonebookAdapter.java
Codice (Java): [Seleziona]
public class PhonebookAdapter extends BaseAdapter implements OnClickListener {
    private Context context;

    private List<Phonebook> listPhonebook;

    public PhonebookAdapter(Context context, List<Phonebook> listPhonebook) {
        this.context = context;
        this.listPhonebook = listPhonebook;
    }

    public int getCount() {
        return listPhonebook.size();
    }

    public Object getItem(int position) {
        return listPhonebook.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup viewGroup) {
        Phonebook entry = listPhonebook.get(position);
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.phone_row, null);
        }
        TextView tvContact = (TextView) convertView.findViewById(R.id.tvContact);
        tvContact.setText(entry.getName());

        TextView tvPhone = (TextView) convertView.findViewById(R.id.tvMobile);
        tvPhone.setText(entry.getPhone());

        TextView tvMail = (TextView) convertView.findViewById(R.id.tvMail);
        tvMail.setText(entry.getMail());

        // Set the onClick Listener on this button
        Button btnRemove = (Button) convertView.findViewById(R.id.phoneRowBtnRemove);
        btnRemove.setOnClickListener(this);
        // Set the entry, so that you can capture which item was clicked and
        // then remove it
        // As an alternative, you can use the id/position of the item to capture
        // the item
        // that was clicked.
        btnRemove.setTag(entry);

        // btnRemove.setId(position);

        CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.phoneRowCheckbox);
        if (checkBox != null) {
                checkBox.setId(position);

        } else
                Log.e("PhonebookAdapter", "checkbox is null");
        return convertView;
    }

    @Override
    public void onClick(View view) {
        Phonebook entry = (Phonebook) view.getTag();
        listPhonebook.remove(entry);
        // listPhonebook.remove(view.getId());
        notifyDataSetChanged();

    }

}

phone_main.xml

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <ListView android:id="@+id/ListView01" android:layout_width="fill_parent"
                android:layout_height="wrap_content"></ListView>
</LinearLayout>

phone_row.xml

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        android:id="@+id/LinearLayout01"
        android:layout_width="fill_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:paddingLeft="10sp"
        android:paddingRight="10sp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="2sp">
        <TextView
                android:layout_height="wrap_content"
                android:layout_width="fill_parent"
                android:id="@+id/tvContact"
                android:text="Name"
                android:typeface="sans"
                android:textSize="16sp"
                android:textStyle="bold"></TextView>
        <LinearLayout
                android:id="@+id/LinearLayout02"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent">
                <TextView
                        android:id="@+id/TextView01"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textStyle="bold"
                        android:text="Mobile  "
                        android:textSize="13sp"></TextView>
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Number"
                        android:id="@+id/tvMobile"
                        android:textSize="13sp"></TextView>
        </LinearLayout>
        <LinearLayout
                android:id="@+id/LinearLayout02"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent">
                <TextView
                        android:id="@+id/TextView01"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textStyle="bold"
                        android:text="Mail  "
                        android:textSize="13sp"></TextView>
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Mail"
                        android:id="@+id/tvMail"
                        android:textSize="13sp"
                        android:layout_weight="1"></TextView>
                <Button
                        android:layout_width="wrap_content"
                        android:id="@+id/phoneRowBtnRemove"
                        android:text="Remove"
                        android:layout_height="40dip"></Button>
                <CheckBox
                        android:id="@+id/phoneRowCheckbox"
                        android:checked="false"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentRight="true" />
        </LinearLayout>

</LinearLayout>

Offline andream1977

  • Utente normale
  • ***
  • Post: 260
  • Respect: +7
    • Mostra profilo
  • Dispositivo Android:
    Nexus S
  • Sistema operativo:
    windows xp
Re:Problema selezione di checkbox in una lista
« Risposta #1 il: 03 Marzo 2011, 10:27:37 CET »
0
Su internet ho trovato che il problema riscontrato rientra in quello che viene chiamato "view recycling"
Per risolverlo bisogna salvarsi una lista che contenga lo stato in cui si trovano i checkbox (cliccato / non cliccato)
Non sono riuscito a trovare un esempio funzionante, vi mostro la cosa migliore che sono riuscito a scrivere, però continua ad avere lo stesso problema
vedete l'errore?

PhonebookAdapter.java
Codice (Java): [Seleziona]
public class PhonebookAdapter extends BaseAdapter {
    private Context context;

    private List<Phonebook> listPhonebook;
    private ArrayList<Integer> checkList = new ArrayList<Integer>();
    public PhonebookAdapter(Context context, List<Phonebook> listPhonebook) {
        this.context = context;
        this.listPhonebook = listPhonebook;
    }

    public int getCount() {
        return listPhonebook.size();
    }

    public Object getItem(int position) {
        return listPhonebook.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup viewGroup) {
        View v = convertView;
        final Phonebook phonebook = (Phonebook)this.getItem(position);
                if (v == null) {
                        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                        v = inflater.inflate(R.layout.phone_row, null);
                }
                CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
                cBox.setTag(position);
                cBox.setText("test");
                if (phonebook.isChecked()) { //<-- non sono convinto di questa riga di codice
                        cBox.setChecked(true); 
                        checkList.add((Integer) cBox.getTag());
                }
                cBox.setOnClickListener(new OnClickListener() {  
                        @Override
                        public void onClick(View v) {
                                CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
                                if (cBox.isChecked()) {
                                        checkList.add((Integer) cBox.getTag());
                                }
                                else if (!cBox.isChecked()) {
                                        checkList.remove(cBox.getTag());
                                }
                        }
                });

                return(v);

    }

}

Phonebook.java

Codice (Java): [Seleziona]
package it.example.list;

public class Phonebook {
        private String name;
        private String phone;
        private String mail;
        private boolean checked;
       
        public Phonebook(String name, String phone, String mail, boolean checked) {
                super();
                this.name = name;
                this.phone = phone;
                this.mail = mail;
                this.checked = checked;
        }
       
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public String getPhone() {
                return phone;
        }
        public void setPhone(String phone) {
                this.phone = phone;
        }
        public String getMail() {
                return mail;
        }
        public void setMail(String mail) {
                this.mail = mail;
        }

        public boolean isChecked() {
                return checked;
        }

        public void setChecked(boolean checked) {
                this.checked = checked;
        }
       
}
« Ultima modifica: 03 Marzo 2011, 10:30:21 CET da andream1977 »

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #2 il: 04 Marzo 2011, 10:40:22 CET »
0
Ti allego un esempio che ho fatto.
Il codice non è molto ottimizzato e per niente elegante, ma non ho tempo per ottimizzarlo...

« Ultima modifica: 04 Marzo 2011, 12:07:11 CET da Ricky` »

Offline andream1977

  • Utente normale
  • ***
  • Post: 260
  • Respect: +7
    • Mostra profilo
  • Dispositivo Android:
    Nexus S
  • Sistema operativo:
    windows xp
Re:Problema selezione di checkbox in una lista
« Risposta #3 il: 04 Marzo 2011, 11:44:52 CET »
0
Ho provato il codice che hai allegato, purtroppo soffre dello stesso problema del mio codice, cioè selezionando un checkbox e poi scrollando la lista in su e giù, la selezione si perde e ne seleziona un altro
Inoltre dopo qualche click crash dando un java.lang.ArrayIndexOutOfBoundsException

:-(

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #4 il: 04 Marzo 2011, 12:07:00 CET »
+2
Hai ragione, nella fretta avevo dimenticato un pezzo :P

Riprova ora, dovrebbe andare ;)

Offline andream1977

  • Utente normale
  • ***
  • Post: 260
  • Respect: +7
    • Mostra profilo
  • Dispositivo Android:
    Nexus S
  • Sistema operativo:
    windows xp
Re:Problema selezione di checkbox in una lista
« Risposta #5 il: 04 Marzo 2011, 12:37:04 CET »
0
Funziona :-)
Adesso mi studio il codice e cerco di capire dove sbaglio
thx

Offline gta77

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #6 il: 23 Agosto 2011, 02:19:16 CEST »
0
Finalmente ho trovato il thread che potrebbe farmi uscire da una pazzia che dura giorni. Ho anche io il problema delle viste reciclate (ormai mi sono fatto una cultura in questo senso). Ho scaricato il tuo codice ma è talmente ben fatto che sinceramente non riesco proprio a capire quanto sia il delta che effettivamente mi serve per risolvere il problema. La mia situazione è un po' diversa, ho un bind su DB della Listview ma suppongo che il concetto sia lo stesso... so che è passato molto tempo dal codice che hai postato... ma non è che potresti scivermi due righe per capire quanto tra PersonViewCache e tutto il resto serva esclusivamente per la risoluzione del problema? grazie mille e scusami per il disturbo. Marco

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #7 il: 23 Agosto 2011, 09:25:34 CEST »
0
Finalmente ho trovato il thread che potrebbe farmi uscire da una pazzia che dura giorni. Ho anche io il problema delle viste reciclate (ormai mi sono fatto una cultura in questo senso). Ho scaricato il tuo codice ma è talmente ben fatto che sinceramente non riesco proprio a capire quanto sia il delta che effettivamente mi serve per risolvere il problema. La mia situazione è un po' diversa, ho un bind su DB della Listview ma suppongo che il concetto sia lo stesso... so che è passato molto tempo dal codice che hai postato... ma non è che potresti scivermi due righe per capire quanto tra PersonViewCache e tutto il resto serva esclusivamente per la risoluzione del problema? grazie mille e scusami per il disturbo. Marco

PersonViewCache non è determinante per la risoluzione del problema. E' presente perchè ho riciclato un tutorial che avevo fatto in precedenza su ArrayAdapter e quindi era già presenta la tecnica del recycle delle view.
Comunque effettivamente mi rendo conto che questa soluzione è decisamente improntata per l'utilizzo con un ArrayAdapter e quindi la portabilità con un Adapter con dati provenienti da DB non è così immediata.
Quello che secondo me dovresti fare è predisporre una struttura dati che ti permette di memorizzare quali righe (tenendoti posizione e/o id del record) sono state selezionate e nel metodo bindView del tuo adapter verificare se la riga in questione è stata selezionata o meno.

Offline gta77

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #8 il: 23 Agosto 2011, 09:50:38 CEST »
0
PersonViewCache non è determinante per la risoluzione del problema. E' presente perchè ho riciclato un tutorial che avevo fatto in precedenza su ArrayAdapter e quindi era già presenta la tecnica del recycle delle view.
Comunque effettivamente mi rendo conto che questa soluzione è decisamente improntata per l'utilizzo con un ArrayAdapter e quindi la portabilità con un Adapter con dati provenienti da DB non è così immediata.
Quello che secondo me dovresti fare è predisporre una struttura dati che ti permette di memorizzare quali righe (tenendoti posizione e/o id del record) sono state selezionate e nel metodo bindView del tuo adapter verificare se la riga in questione è stata selezionata o meno.

Grazie mille per questo consiglio... lo applicherò stasera stesso e ti aggiornerò ;)
Mi sorge un solo dubbio... ok per tenere traccia delle selezione per visualizzare o meno un'immagine associata alla riga, ma alla pressione della riga faccio partire anche un countdown nella riga stessa che ha lo stesso problema e "sparisce" magicamente allo scroll. Non essendo tipo booleano da poter gestire con questo nuovo array come posso fare? mi memorizzo anche un timestamp e nel binnView mi faccio partire il countdown da now-timestamp? Grazie infinite!

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #9 il: 23 Agosto 2011, 10:00:16 CEST »
0
Grazie mille per questo consiglio... lo applicherò stasera stesso e ti aggiornerò ;)
Mi sorge un solo dubbio... ok per tenere traccia delle selezione per visualizzare o meno un'immagine associata alla riga, ma alla pressione della riga faccio partire anche un countdown nella riga stessa che ha lo stesso problema e "sparisce" magicamente allo scroll. Non essendo tipo booleano da poter gestire con questo nuovo array come posso fare? mi memorizzo anche un timestamp e nel binnView mi faccio partire il countdown da now-timestamp? Grazie infinite!

Potrebbe essere una soluzione :P

Offline gta77

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
Re:Problema selezione di checkbox in una lista
« Risposta #10 il: 23 Agosto 2011, 23:43:23 CEST »
0
Potrebbe essere una soluzione :P

Scusami ma sto diventando scemo... ancora di +  :-)
Seguendo il tuo consiglio ho creato un
Codice (Java): [Seleziona]
static ArrayList<String> statusSms = new ArrayList<String>(); che tiene traccia delle righe cliccate ed in base a questo ho inserito
Codice (Java): [Seleziona]
                if(statusSms.get(c.getPosition())== "0"){
                        sms.setVisibility(View.INVISIBLE);
all'interno della funzione
Codice (Java): [Seleziona]
void populateFrom(Cursor c, BookingHelper helper) richiamata dal bind. Ti ricordo che ho una listactivity con due ulteriori componenti (textview e imageview). Funziona benissimo per l'immagine nella riga ma il coutdown (textview) compare e scompare su diverse righe come prima... sarà che non è applicabile a questo oggetto? ti incollo il codice che utilizzo per far comparire la stringa:
Codice (Java): [Seleziona]
        public void setCountDown(){
        final TextView dt = (TextView)currentView.findViewById(R.id.countDownList);
        final CountDownTimer myTimer = new CountDownTimer(Long.parseLong(prefs.getString("timeWait", null))*60000, 1000) {                            
            public void onTick(long millisUntilFinished) {
                dt.setText("Arrivo previsto tra " + millisUntilFinished/60000 + " minuti");
            }
            public void onFinish() {
                dt.setText("Arrivato?");
            }
        };
        myTimer.start();
        }
Riesce a darmi un altro prezioso consiglio? sto leggendo veramente centinaia di post ovunque ma ho trovato un esempio di coutdown fatto su una intera listactivity che non riesco a "mappare" nel mio caso. Ti riporto il codice che ho trovato, magari qualcuno che ci capisce sicuramente più di me può darmi una mano:

Codice (Java): [Seleziona]
package com.rochdev.example.countdownlistview;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;

public class CountDownList extends ListActivity {

        private Button mButton;

        private HashMap<Integer, TextView> mCounterList = new HashMap<Integer, TextView>();
        private ArrayList<MyData> mDataList = new ArrayList<MyData>();

        private Handler mHandler;
        private boolean mCountersActive;

        public CountDownList() {
                mHandler = new Handler();
        }

        private final Runnable mRunnable = new Runnable() {
                public void run() {
                        MyData myData;
                        TextView textView;

                        // if counters are active
                        if (mCountersActive) {                         
                                if (mCounterList != null && mDataList != null) {
                                        for (int i=0; i < mDataList.size(); i++) {
                                                myData = mDataList.get(i);
                                                textView = mCounterList.get(i);
                                                if (textView != null) {
                                                        if (myData.getCount() >= 0) {
                                                                textView.setText(myData.getCountAsString());
                                                                myData.reduceCount();
                                                        }
                                                }
                                        }
                                }
                                // update every second
                                mHandler.postDelayed(this, 1000);
                        }
                }
        };

        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);

                // start and stop button
                mButton = (Button) findViewById(R.id.myButton);
                mButton.setText("Stop");
                mButton.setOnClickListener(new OnClickListener() {                     
                        @Override
                        public void onClick(View v) {                  
                                stopStart();
                        }
                });

                // add some test data
                mDataList = new ArrayList<MyData>();
                MyData a = new MyData("Start 1000", 1000);
                MyData b = new MyData("Start 900", 900);
                MyData c = new MyData("Start 800", 800);
                MyData d = new MyData("Start 700", 700);
                MyData e = new MyData("Start 600", 600);
                MyData f = new MyData("Start 500", 500);
                MyData g = new MyData("Start 400", 400);
                MyData h = new MyData("Start 300", 300);
                MyData i = new MyData("Start 200", 200);
                MyData j = new MyData("Start 100", 100);
                MyData k = new MyData("Start 50", 50);
                MyData l = new MyData("Start 10000", 10000);
                mDataList.add(a);
                mDataList.add(b);
                mDataList.add(c);
                mDataList.add(d);
                mDataList.add(e);
                mDataList.add(f);
                mDataList.add(g);
                mDataList.add(h);
                mDataList.add(i);
                mDataList.add(j);
                mDataList.add(k);
                mDataList.add(l);

                initData();
        }

        private void initData() {
                // set the list adapter
                setListAdapter(new MyListAdapter(this, R.layout.row, mDataList));
                // start counters
                stopStart();
        }      

        private void stopStart() {
                if (mCountersActive) {
                        mCountersActive = false;
                        mButton.setText("Start");
                } else {
                        mCountersActive = true;
                        mHandler.post(mRunnable);
                        mButton.setText("Stop");
                }
        }

        private class MyListAdapter extends ArrayAdapter<MyData> {

                private ArrayList<MyData> items;

                public MyListAdapter(Context context, int textViewResourceId,
                                ArrayList<MyData> items) {
                        super(context, textViewResourceId, items);
                        this.items = items;
                }

                @Override
                public View getView(int position, View convertView, ViewGroup parent) {                                        
                        LayoutInflater vi = (LayoutInflater)
                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                        View v = vi.inflate(R.layout.row, null);

                        MyData myData = items.get(position);

                        if (myData != null) {
                                TextView text = (TextView) v.findViewById(R.id.myTextView);
                                if (text != null) {
                                        text.setText(myData.getText());
                                }

                                TextView counter = (TextView) v.findViewById(R.id.myTextViewTwo);
                                if (counter != null) {
                                        counter.setText(myData.getCountAsString());
                                        // add the TextView for the counter to the HashMap.
                                        mCounterList.put(position, counter);
                                }
                        }

                        return v;
                }              
        }

        private class MyData {
                private String text;
                private int count;

                public MyData(String text, int count) {
                        this.text = text;
                        this.count = count;
                }

                public String getText() {
                        return text;
                }

                public int getCount() {
                        return count;
                }

                public String getCountAsString() {
                        return Integer.toString(count);
                }

                public void reduceCount() {
                        if (count > 0) {
                                count--;
                        }
                }
        }
}