Question

In my activity, my layout is a listview, with complex row items. So I have write a class wich is a custom ArrayAdapter. From my activity, I call my ArrayAdapter and I have tried to set listener and get position of imagebutton click, but it doesn't work. Position is not set at the right value because it's the position of the last view that android need to display the screen.But how can i get the right position of the row that had been click ? I mean for example if I have 10 rows in my listView and I click the row item 5, the information that i want with the toast is the name of user number 5, but toast display the username of the row in position number 10... Please help i can't find solutions ! thank you !

here is the code of my arrayadpater:

public class AudioListAdapter extends ArrayAdapter<DonneesListeAudio>  {

// Variables
private Activity activity;
private ArrayList<DonneesListeAudio> DataOfListView;
private static LayoutInflater Inflater = null;
int classPosition=0;

//Constructeur
public AudioListAdapter(Activity activity, int textViewResourceId, ArrayList<DonneesListeAudio> _Liste) {
     super(activity, textViewResourceId, _Liste);
    try {
        this.activity = activity;
        this.DataOfListView = _Liste;
        Inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    } catch (Exception e) {
    }
}

//construction de la vue de l'item
public View getView(int position, View convertView, ViewGroup parent) {
    classPosition = position;
    View ItemView = convertView;
    ViewWrapper Holder;
    try {
        if (convertView == null) {
            ItemView = Inflater.inflate(R.layout.row_liste_audio, null);  /* création de la vue */

            Holder = new ViewWrapper(ItemView);                           /* création d'une instance de wrapper pour conservation des objets de la vue ( textview etc .. )dans le tag de la vue  */

            //  >>>>>>>>>>>>>>>   HERE WAS MY LISTENER BEFORE HASSAN ANSWER
            ImageButton MyImageButton = (ImageButton) Holder.getBase().findViewById(R.drawable.ic_playvert);        /* listner 1 */
            MyImageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast ToastCourt = Toast.makeText(getContext(), DataOfListView.get(classPosition).getPseudoUser(), Toast.LENGTH_SHORT);
                    ToastCourt.show();
                }
            });
            ItemView.setTag(Holder);                                      /* sauvegarde du Wrapper de nom Holder dans le tag de la vue crée*/
        } else {
            Holder = (ViewWrapper) ItemView.getTag();                     /* récupération des objets de la vue ( textview etc .. ) via le Wrapper stocké dans le tag */
        }
        chargementDesDonneesDeItem(Holder, position);                     /* chargement des données provenants de MyApplication dans le Wrapper de nom Holder */
    } catch (Exception e) {
    }
    return ItemView;
}

and here is my listactivity wich call my arrayadapter name AudioListAdapter

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    requestWindowFeature(Window.FEATURE_NO_TITLE);    /* suppresion barre de titre */
    setContentView(R.layout.activity_audio);

    //footer (pied de page) de la listView ( à appeler avant l'adapteur )
    View footer = getLayoutInflater().inflate(R.layout.footer, null);
    ListView listView = getListView();
    listView.addFooterView(footer);

    //chargement des données de la premeire page de la listview via LA thread
    chargeListe(0, "PremierePage", "aucun");
    setListAdapter(new AudioListAdapter(this, 0, MyApplication.getMyArrayDonneesListeAudio()));

SOLUCE : Here is my code of arrayadapter modified with the solution of Hassan ( move the setlistener outside the IF statement ) and the solution of Rick Falck ( save the position in the tag of the imageview). And it works ! THANK YOU SO MUCH ! ( see comments in the code below )

public View getView(int position, View convertView, ViewGroup parent) {
    classPosition = position;
    View ItemView=convertView;

    try {
        if (convertView == null) {
            convertView = Inflater.inflate(R.layout.row_liste_audio, null);  /* création de la vue */

            Holder = new ViewWrapper(convertView);                           /* création d'une instance de wrapper pour conservation des objets de la vue ( textview etc .. )dans le tag de la vue  */

            convertView.setTag(Holder);                                      /* sauvegarde du Wrapper de nom Holder dans le tag de la vue crée*/

        } else {

            Holder = (ViewWrapper) convertView.getTag();                     /* récupération des objets de la vue ( textview etc .. ) via le Wrapper stocké dans le tag */


        };


        chargementDesDonneesDeItem(Holder, position);                        /* chargement des données provenants de MyApplication dans le Wrapper de nom Holder */


        ImageView MyImageView = (ImageView)convertView.findViewById(R.id.image_media_play);     /* get instance of the button */
        PositionObject TagPosition = new PositionObject();                                      /* create a new object for tag ( just save position as an INT */
        TagPosition.setPosition(classPosition);                                                 /* set position in the object for tag */
        MyImageView.setTag(TagPosition);                                                        /* save tag with position  */
        MyImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {                                              /* set the listener here to be sure that listener exist even when items convertview are recycled  */
                int idx;
                PositionObject MyPosition = (PositionObject) view.getTag();                     /* get the tag of the view that was click */
                idx=MyPosition.getPosition();                                                   /* get the position of the view in the listitem ! */
                Toast ToastCourt = Toast.makeText(getContext(), DataOfListView.get(idx).getPseudoUser(), Toast.LENGTH_SHORT);
                ToastCourt.show();


            }
        });




    } catch (Exception e) {
            e.getCause();
            e.getLocalizedMessage();
            e.toString();
            e.printStackTrace();


    }
    return convertView;
}
Was it helpful?

Solution

Simply take the following out of the if statement scope and after the else scope.

You need to do that every time:

final int positionForListener = position;
ImageButton MyImageButton = (ImageButton) Holder.getBase().findViewById(R.drawable.ic_playvert);        /* listner 1 */
            MyImageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast ToastCourt = Toast.makeText(getContext(), DataOfListView.get(classPosition).getPseudoUser(), Toast.LENGTH_SHORT);
                    ToastCourt.show();
                    Log.i("position", ""+positionForListener);
                }
            });

Based on this logic you need to reconsider the other line of codes and where to set them. But, for now this solves your problem.

This works too. define a final position var for listener then use it with in the listener.

OTHER TIPS

The problem is that View.OnClickListener is an inner class to AudioListAdapter. The getView() method is called by the adapter when it needs to draw an item. It will have the position of the item to draw.

The onClick() method will be called when the ImageView is clicked. At that time, the data in the outer class is going to represent the last item drawn, not the one clicked. So, classPosition will be the last item drawn, which is #10.

The View passed into onClick() is the ImageView itself. You need to figure out what item it belongs to. The only thing I can think of is to put the position of the item into the ImageView.Tag (ImageView.setTag()). Then in onClick() you get the position (ImageView.getTag()).

Then you can call getItem(posFromTag) on that position to get the item in your DataOfListView. From there you can get the other info you need.

Don't set a listener when setting up a view that will be recycled. When it's recycled, the listener will be too, and it will have the wrong position associated with it.

Various potential solutions:

  • Don't recycle views. It's less efficient, but if you inflate and populate a new view every time, you won't have problems with data from recycled views being recycled.
  • Use AdapterView.setOnItemClickListener instead of a button. The whole list item is clickable instead of just the button, and the correct position is taken care of automatically.
  • Set the listener as part of setting a recycled view, instead of a new one.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top