Recyclerview滚动期间更改项目

时间:2015-08-18 06:40:32

标签: android android-scrollview android-recyclerview

我有一个RecyclerView。每行都有一个播放按钮,textview和Progressbar。当点击播放按钮时必须播放我的SD卡中的音频并且必须进度Progressbar 问题是当我向下滚动recyclerview时,请更改下一行中的进度条。这意味着我可以同时在屏幕上显示5个项目。当我滚动到第6行,第6行搜索栏突然改变。

public class ListAdapter extends RecyclerView.Adapter {

    private List<Historyitem> stethitems;
    public Context mContext;
    public Activity activity;
    public Handler mHandler;

    static MediaPlayer mPlayer;
    static Timer mTimer;

    public ListAdapter(Activity activity,Context mContext,List<Historyitem> stethitems) {
        this.stethitems = stethitems;
        this.mContext = mContext;
        this.activity = activity;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View rootView = LayoutInflater.
                from(mContext).inflate(R.layout.stethoscopeadapteritem, null, false);
        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        rootView.setLayoutParams(lp);
        mHandler = new Handler();
        return new MyViewHolder(rootView);
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {

        final Historyitem dataItem = stethitems.get(position);
        final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
        myViewHolder.progressplay.setProgress(0);
        myViewHolder.stethdatetime.setText(dataItem.getReported_Time());
        myViewHolder.stethhosname.setText(dataItem.getdiv());

        if(dataItem.getPatient_Attribute().replaceAll(" ","").equals("")){
            myViewHolder.stethdoctorname.setText(dataItem.getunit());
        } else {
            myViewHolder.stethdoctorname.setText(dataItem.getPatient_Attribute());
        }

        myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                   FileDownload(dataItem.getmsg(),
                            myViewHolder.progressplay);

            }
        });
    }

    @Override
    public int getItemCount() {

        return stethitems.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        final CustomTextRegular stethdatetime;
        final CustomTextView stethhosname;
        final CustomTextBold stethdoctorname;
        final ImageButton stethstreamplay;
        final NumberProgressBar progressplay;

        public MyViewHolder(View itemView) {
            super(itemView);

            stethdatetime = (CustomTextRegular)
                    itemView.findViewById(R.id.stethdatetime);
            stethhosname = (CustomTextView)
                    itemView.findViewById(R.id.stethhosname);
            stethdoctorname = (CustomTextBold)
                    itemView.findViewById(R.id.stethdoctorname);
            stethstreamplay = (ImageButton)
                    itemView.findViewById(R.id.stethstreamplay);
            progressplay= (NumberProgressBar)
                    itemView.findViewById(R.id.progressplay);


        }
    }
    public void  FileDownload(final String downloadpath,

                                     final NumberProgressBar progressplay) {

        new AsyncTask<NumberProgressBar, Integer, NumberProgressBar>() {
            NumberProgressBar progress;
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                try {
                    if(mPlayer!=null){
                        mPlayer.stop();
                    }
                }catch (Exception e){
                }
                try {
                    if(mTimer != null){
                        mTimer.purge();
                        mTimer.cancel();
                    }
                }catch (Exception e){
                }
            }

            @Override
            protected NumberProgressBar doInBackground(NumberProgressBar... params) {
                int count;
                progress = progressplay;
                try {

                    final List<NameValuePair> list = new ArrayList<NameValuePair>();
                    list.add(new BasicNameValuePair("pid",id));

                    URL url = new URL(Config.requestfiledownload + "?path=" +
                            downloadpath);
                    URLConnection connection = url.openConnection();
                    connection.connect();

                    int lenghtOfFile = connection.getContentLength();
                    // download the file
                    InputStream input = new BufferedInputStream(url.openStream());
                    OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() +
                            "record.wav");
                    byte data[] = new byte[1024];
                    long total = 0;
                    while ((count = input.read(data)) != -1) {
                        total += count;
                        // publishing the progress....
                        publishProgress((int) (total * 100 / lenghtOfFile));
                        output.write(data, 0, count);
                    }
                    output.flush();
                    output.close();
                    input.close();
                } catch (Exception e) {

                }
                return progress;
            }
            @Override
            protected void onPostExecute(final NumberProgressBar numberProgressBar) {
                super.onPostExecute(numberProgressBar);

                        try {
                            StartMediaPlayer(numberProgressBar);
                        } catch (Exception e){
                            e.printStackTrace();
                        }

            }
        }.execute();
    }

    public void StartMediaPlayer(final NumberProgressBar progressbar){
        Uri playuri = Uri.parse("file:///sdcard/record.wav");
        mPlayer = new MediaPlayer();
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.reset();
        try {
            mPlayer.setDataSource(mContext, playuri);
        } catch (IllegalArgumentException e) {

        } catch (SecurityException e) {

        } catch (IllegalStateException e) {

        } catch (Exception e) {

        }
        try {
            mPlayer.prepare();
        } catch (Exception e) {

        }

        mPlayer.start();
        progressbar.setMax(mPlayer.getDuration());
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if(mPlayer!=null) {
                    mPlayer.release();
                    progressbar.setProgress(0);
                }
                if(mTimer != null){
                    mTimer.purge();
                    mTimer.cancel();
                }
            }
        });
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        progressbar.setProgress(mPlayer.getCurrentPosition());
                    }
                });
            }
        },0,500);
    }}

14 个答案:

答案 0 :(得分:155)

请试试这个

  1. 如果您使用ListView - 请覆盖以下方法。

    @Override
    public int getViewTypeCount() {    
        return getCount();
    }
    
    @Override
    public int getItemViewType(int position) {    
        return position;
    }
    
  2. 如果您使用RecycyclerView - 仅覆盖getItemViewType()方法。

    @Override
    public int getItemViewType(int position) {    
        return position;
    }
    

答案 1 :(得分:35)

在适配器构造函数中添加setHasStableIds(true);并在适配器中覆盖这两个方法。

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

@Override
public int getItemViewType(int position) {
       return position;
}

答案 2 :(得分:25)

顾名思义,RecyclerView中的视图会在您向下滚动时被回收。这意味着您需要保留支持模型中每个项目的状态,在这种情况下为Historyitem,并在onBindViewHolder中恢复。

1)创建位置,最大值以及保存模型中ProgressBar状态所需的其他变量。

2)根据背景模型中的数据设置ProgressBar的状态;点击后,将项目的位置传递到FileDownload / StartMediaPlayer方法。

public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
    final Historyitem dataItem = stethitems.get(position);
    final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
    myViewHolder.progressplay.setMax(dataItem.getMax());
    myViewHolder.progressplay.setProgress(dataItem.getPosition());
    ...
    myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
               FileDownload(dataItem.getmsg(), position);
        }
    });

3)通过更新支持模型并通知它已被更改来更新进度条。

stethitems.get(position).setPosition(mPlayer.getCurrentPosition());
notifyItemChanged(position);

答案 3 :(得分:2)

当我们动态更改RecyclerView个项目时(即,更改特定RecyclerView项目的背景颜色时),由于{ {1}}重用其项目。

但是要避免这种情况,可以使用RecyclerView周围的android.support.v4.widget.NestedScrollView并让RecyclerView处理滚动。

NestedScrollView

然后在代码中,您可以为<android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> </android.support.v4.widget.NestedScrollView> 禁用嵌套滚动,以仅允许RecyclerView处理滚动来平滑滚动。

NestedScrollView

答案 4 :(得分:1)

recylerView放入NestedScroll View的{​​{1}}中,并添加属性XML

然后在适配器nestedScrollingEnabled = false上添加以下行

onBindViewHolder

将此final MyViewHolder viewHolder = (MyViewHolder)holder; 对象与您的视图一起用于viewHolder或进行任何类型的点击事件。

例如setText

答案 5 :(得分:0)

我在处理大量数据时遇到了同样的问题,它与5一起工作,因为它渲染了屏幕上可见的五个元素,但这给了概念更多的元素。事情是......

有时,RecyclerView和listView只会跳过填充数据。如果在滚动时跳过了RecyclerView绑定功能,但是当您尝试调试recyclelerView适配器时,它将正常工作,因为它每次都会调用onBind,您还可以看到官方谷歌开发人员的视图The World of listView。大约20分钟-30分钟,他们将解释你永远不会假设每次都会调用getView的位置。

所以,我建议使用

RecyclerView DataBinder created by satorufujiwara.

RecyclerView MultipleViewTypes Binder created by yqritc.

如果你发现那些易于解决的问题,可以使用其他粘合剂。

这是处理MultipleView类型或使用大量数据的方法。这些粘合剂可以帮助您 只需仔细阅读文档即可修复它,和平!!

答案 6 :(得分:0)

此行在每个绑定上将进度更改为0

myViewHolder.progressplay.setProgress(0);

将其状态保存在某处,然后将其加载到同一行。

答案 7 :(得分:0)

为什么不尝试这样做,

    HashMap<String, Integer> progressHashMap = new HashMap<>();

    //...
    if(!progressHashMap.containsKey(downloadpath)){
        progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
    }

    progressbar.setProgress(progressHashMap.get(downloadpath));

答案 8 :(得分:0)

试试这个

@Override public void smoothScrollToPosition(RecyclerView    recyclerView, RecyclerView.State state,
       int position) {    LinearSmoothScroller linearSmoothScroller =
           new LinearSmoothScroller(recyclerView.getContext()) {
               @Override
               public PointF computeScrollVectorForPosition(int targetPosition) {
                   return LinearLayoutManager.this
                           .computeScrollVectorForPosition(targetPosition);
               }
           };    linearSmoothScroller.setTargetPosition(position);    startSmoothScroll(linearSmoothScroller); }

see this also

答案 9 :(得分:0)

在尝试实现一个recyclerview时遇到了同样的问题,该视图包含一个edittex和一个复选框作为行元素。我只是通过在适配器类中添加以下两行来解决滚动值更改问题。

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

@Override
public int getItemViewType(int position) {
    return position;
}

我希望这将是一个可能的解决方案。谢谢

答案 10 :(得分:0)

覆盖适配器中的方法 getItemViewType 。在Kotlin中使用

override fun getItemViewType(position: Int): Int {
    return position
}

答案 11 :(得分:0)

如果您的recyclerview ViewHolder具有更多逻辑或具有不同的其他视图,则应尝试:

 ORDER BY DOCID,
          DOC_VERSION DESC,
          DATE_LOG,
          DECODE(EVENT_DESC,'Document Submitted for Deployment',1,
                            'Document Deployed',2,
                 3) -- added this 

其中x是列表的大小。以上对我有用,我希望对您也有用。

答案 12 :(得分:-2)

这是recyclerView的预期行为。由于视图已被回收,因此您的商品可能会进入随机视图。要解决这个问题,您必须自己指定将哪个项目放入哪种视图中。此信息可以保存在SparseBooleanArray中。你可以做的是在你的适配器中像这样

创建一个SparseBooleanArray
SparseBooleanArray selectedItems = new SparseBooleanArray();

每当您的观点发生变化时,请执行以下操作:

selectedItems.put(viewItemIndex,true);

现在在你的onBindViewHolder上做

 if(selectedItems.get(position, false)){
    //set progress bar of related to the view to desired position
    }
    else {
        //do the default
    }

这是解决问题的基础。您可以将此逻辑调整为recyclerView中的任何类似问题。

答案 13 :(得分:-2)

我遇到了类似的问题,并大量搜索了正确的答案。基本上,这是回收站视图的一种设计,它可以更新滚动视图,因为它可以刷新视图。

因此,您要做的就是在绑定时告诉它不要刷新它。

这就是您的onBindViewHolder的外观

@Override
@SuppressWarnings("unchecked")
public void onBindViewHolder(final BaseViewHolder holder, final int position) {
    holder.bind(mList.get(position));

    // This is the mighty fix of the issue i was having
    // where recycler view was updating the items on scroll.
    holder.setIsRecyclable(false);
}