Recyclerview Изменение элементов во время прокрутки

У меня есть RecyclerView. В каждой строке есть кнопка воспроизведения, текстовое окно и Progressbar. При нажатии на кнопку воспроизведения необходимо воспроизвести звук с моей SD-карты и выполнить прогресс. Пробковая панель. Проблема заключается в том, что я прокручиваю вниз, чтобы переработать изменения в Progressbar в следующей строке. Я могу поместить 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); }} 

Как следует из названия, представления в RecyclerView перерабатываются при прокрутке вниз. Это означает, что вам нужно сохранить состояние каждого элемента в вашей модели Historyitem , что в этом случае будет Historyitem , и восстановить его в вашем onBindViewHolder .

1) Создайте позицию, max и любые другие переменные, необходимые для сохранения состояния 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); 

Попробуйте это

  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; } 

Добавьте setHasStableIds(true); В конструкторе адаптера и переопределите эти два метода в адаптере.

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

попробуй это

 @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); } 

См. Также

У меня была такая же проблема при обработке большого количества данных, она работает с 5, потому что она отображает пять элементов, которые видны на экране, но это дает проблему с большим количеством элементов. Дело в том ..

Иногда RecyclerView и listView просто пропускают Populating Data. В случае, если функция привязки RecyclerView пропускается во время прокрутки, но при попытке и отладке адаптера recyclerView она будет работать нормально, так как она будет вызывать onBind каждый раз, вы также можете увидеть официальное представление разработчика Google The World of listView . Примерно через 20 минут -30 минут они объяснят, что вы никогда не сможете предположить, что getView по позиции будет вызываться каждый раз.

Поэтому я предлагаю использовать

RecyclerView DataBinder, созданный satorufujiwara.

или

RecyclerView MultipleViewTypes Binder, созданный yqritc.

Это другие доступные Binders, если вы найдете их легкими в работе.

Это способ иметь дело с типами MultipleView или если вы используете большой объем данных. Эти связующие могут помочь вам просто внимательно прочитать документацию, чтобы исправить это, мир!

Эта строка изменяет ход до 0 при прокрутке

 myViewHolder.progressplay.setProgress(0); 

Сохраните его состояние где-нибудь, затем загрузите его в эту же строку.

Почему бы вам не попробовать так,

  HashMap<String, Integer> progressHashMap = new HashMap<>(); //... if(!progressHashMap.containsKey(downloadpath)){ progressHashMap.put(downloadpath, mPlayer.getCurrentPosition()); } progressbar.setProgress(progressHashMap.get(downloadpath)); 

Это ожидаемое поведение 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.