1

I have got a list view with 9 rows in it. Every row has two TextViews and a ImageButton which plays a song specific for that row. If it is playing one of the two TextViews should change color and change the text every second to get a result like '1:12 - 7:35'. And that's where my problem lies.

The first time the list view loads all elements that are on screen work fine but whenever I scroll down, tap on the playButton it highlights the wrong cell. Probably because list view's position returns the position on the screen and not the position in the list.

private MediaPlayer mp;
private Handler handler;
private int playingCellPosition = -999;

public View getView(final int position, View convertView, final ViewGroup parent) {

    // Find the oefening to work with
    final Oefening currentExercise = myExercises.get(position);

    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View itemView = vi.inflate(R.layout.cell, null);

    // Get textviews
    final TextView durationTextView = (TextView) itemView.findViewById(R.id.cell_duur);

    final Runnable updateDurationTextView = new Runnable() {
        @Override
        public void run() {
            runOnUiThread(new Runnable(){
                public void run(){
                    Oefening playingExercise = currentExercise.get(playingCellPosition);

                    TextView durationTextViewToUpdate = (TextView) parent.getChildAt(playingCellPosition).findViewById(R.id.cell_duur);
                    durationTextViewToUpdate.setText(getFormattedCurrent(mp.getCurrentPosition()) + " - " + playingExercise.getDuration());
                    durationTextViewToUpdate.setTextColor(Color.parseColor("#b71393"));
                }
            });

            handler.postDelayed(this, 1000);
        }
    };

    ImageButton playButton = (ImageButton) itemView.findViewById(R.id.cell_playButton);
    playButton.setOnClickListener(new OnClickListener() {
        public void onClick(final View v) {
            if (mp.isPlaying()) {
                // Pause it here. Not very important to this problem since it occurs when it starts playing and not when it stops
                mp.pause();
                v.setBackgroundResource(R.drawable.play_icon);

                durationTextView.setText(currentExercise.getDuration());
                durationTextView.setTextColor(Color.BLACK);

                handler.removeCallbacks(updateDurationTextView);
            } else {
                mp = MediaPlayer.create(MainActivity.this, currentExercise.getAudioFile());
                mp.start();

                v.setBackgroundResource(R.drawable.pause_icon);

                handler.post(updateDurationTextView);
           }
        }
    });
}

The Oefening playingExercise = currentExercise.get(playingCellPosition); works fine though, since it shows the information of the cell whose play button I tapped on. It just shows the information on the wrong cell.

As Áron Nemmondommegavezetéknevem pointed out, the problem is in parent.getChildAt(...);

Note 1: I don't reuse views with convertView since that messed up positions a lot. This is the closest I have come to what I have to achieve.

Note 2: I left out a lot of the code for the MediaPlayer. It is constructed well, so don't worry about that.

Note 3: If someone has a better suggestion for a title, please edit this one. Couldn't come up with a better one.

Community
  • 1
  • 1
yoeriboven
  • 3,541
  • 3
  • 25
  • 40

2 Answers2

0

The problem is obviously with

parent.getChildAt(...);

In the case of a ListView it doesn't return the view of the specific position. Actually it's quite unpredictable what it returns with.

To illustrate why it doesn't return with the view of the specified position: imagine a list view with 10000 or more items. ListView has only a few views, and doesn't have views for all the 10000 items. What could it return with if you would request the 2786. view? Nothing, it doesn't have a view for that item.

Edit: Suggestion: Although I don't see how your code works, you should store which item view belongs to an individual item. For example, you can call setTag(position) on convertView before you return with it. Then you can write a function which finds the appropriate view for an item, if it exists. Something similar to this:

public View findViewAtPosition(int position) {
    for (int i=0; i < listView.getChildCount(); i++) {
        if (listView.getChildAt(i).getTag() == position) {
            return(listView.getChildAt(i));
        }
    }
    return(null);
}
Aron Lorincz
  • 1,677
  • 3
  • 19
  • 29
0

I fixed it with an answer on another topic: https://stackoverflow.com/a/2679284/1352169

Áron Nemmondommegavezetéknevem's answer looks good, but this one is a little bit better since it e.g. keeps headers in mind too.

Community
  • 1
  • 1
yoeriboven
  • 3,541
  • 3
  • 25
  • 40