SeekBar和ListView回收问题

时间:2015-07-14 01:44:53

标签: android listview seekbar

我在我的新应用程序中使用此项目,该应用程序显示带有播放按钮和SeekBar进度的曲目列表。我能够播放曲目但是我在更新SeekBar时遇到了问题。

我使用Runnable和Handler来更新SeekBar。 当我点击游戏时,该子视图的SeekBar正确移动,但处于可回收位置的孩子也得到了更新。例如,我有一个包含10个项目的列表,仅包含5个可见项目。当第一首曲目的SeekBar得到更新时,第6首曲目也进行了更新。如果我有更大的名单,同样的事情发生在第11或第16位...... 有关如何正确更新它的任何建议吗?

这是适配器

public class ListViewAdapter extends BaseAdapter {
    private Activity activity;
    private List<Ring> list;
    private LayoutInflater inflater;
    private int mediaFileLengthInMilliseconds;
    private final Handler handler = new Handler();
    private MediaPlayer player;
    private AssetManager assetManager;

    public ListViewAdapter(Activity activity, List<Ring> list) {
        this.activity = activity;
        this.list = list;
        this.inflater = LayoutInflater.from(this.activity);
        assetManager = activity.getAssets();
        player = new MediaPlayer();
    }


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

    @Override
    public Ring getItem(int position) {
        return list.get(position);
    }

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


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

        final ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = this.inflater.inflate(R.layout.list_view_item, parent, false);

            holder.play = (ImageButton) convertView.findViewById(R.id.play);
            holder.fav = (Button) convertView.findViewById(R.id.fav);
            holder.set = (Button) convertView.findViewById(R.id.setAs);
            holder.title = (TextView) convertView.findViewById(R.id.title);
            holder.seekBarProgress = (SeekBar) convertView.findViewById(R.id.bar);
            holder.seekBarProgress.setMax(99);
            holder.seekBarProgress.setEnabled(false);
            convertView.setTag(holder);

        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.title.setText(list.get(position).getName());
        holder.title.setTypeface(Typeface.createFromAsset(activity.getAssets(), "fonts/OpenSans-Light.ttf"));
        holder.play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (player.isPlaying()) {
                    player.pause();
                    holder.play.setImageDrawable(ResourcesCompat.getDrawable(activity.getResources(), android.R.drawable.ic_media_play, null));
                    holder.primarySeekBarProgressUpdater();
                } else {
                    player.reset();
                    AssetFileDescriptor afd = null;
                    try {
                        afd = assetManager.openFd(list.get(position).getName() + ".mp3");
                        player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                        player.prepare();
                        player.start();
                        mediaFileLengthInMilliseconds = player.getDuration();
                        player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
                            @Override
                            public void onBufferingUpdate(MediaPlayer mp, int percent) {
                                holder.seekBarProgress.setSecondaryProgress(percent);
                            }
                        });
                        holder.seekBarProgress.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                if (v.getId() == R.id.bar) {
                                    if (player.isPlaying()) {
                                        SeekBar sb = (SeekBar) v;
                                        int playPositionInMillisecconds = (mediaFileLengthInMilliseconds / 100) * sb.getProgress();
                                        player.seekTo(playPositionInMillisecconds);
                                    }
                                }
                                return true;
                            }
                        });
                        player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                            @Override
                            public void onCompletion(MediaPlayer mp) {
                                holder.play.setImageDrawable(ResourcesCompat.getDrawable(activity.getResources(), android.R.drawable.ic_media_play, null));
                            }
                        });
                        holder.primarySeekBarProgressUpdater();
                        holder.play.setImageDrawable(ResourcesCompat.getDrawable(activity.getResources(), android.R.drawable.ic_media_pause, null));
                    }catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        return convertView;
    }

    private class ViewHolder {
        TextView title;
        ImageButton play;
        Button set;
        Button fav;
        SeekBar seekBarProgress;

        void primarySeekBarProgressUpdater() {
            seekBarProgress.setProgress((int) (((float) player.getCurrentPosition() / mediaFileLengthInMilliseconds) * 100)); // This math construction give a percentage of "was playing"/"song length"
            if (player.isPlaying()) {
                Runnable notification = new Runnable() {
                    public void run() {
                        primarySeekBarProgressUpdater();
                    }
                };
                handler.postDelayed(notification,100);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

正如您已经指出的那样,列表视图项目被回收。因此,您的Handler应该使用SeekBar的值更新支持数据模型,并在适配器上调用notifyDataSetChanged()SeekBar值的实际设置应由适配器的getView()处理。

这不是一个完美的解决方法,因为您的代码存在很多问题,但它应该解决您正在更新的多个列表项的问题。

  1. position变量添加到支持列表模型
  2. 将您要更新的项目的位置传递到primarySeekBarProgressUpdater
  3. 致电notifyDataSetChanged()
  4. getView中,根据您的支持数据模型设置搜索栏位置
  5. void primarySeekBarProgressUpdater(final int i) {
        list.get(i).setPosition((int) (((float) player.getCurrentPosition() / mediaFileLengthInMilliseconds) * 100)); // This math construction give a percentage of "was playing"/"song length"
        notifyDataSetChanged();
        if (player.isPlaying()) {
            Runnable notification = new Runnable() {
                public void run() {
                    primarySeekBarProgressUpdater(i);
                }
            };
            handler.postDelayed(notification,100);
        }
    }
    
    public View getView(final int position, View convertView, ViewGroup parent) {
        ...
        holder.seekBarProgress.setProgress(list.get(position).getPosition());
        ...
    }