Modification de la vue d’ensemble des articles lors du défilement

J’ai un RecyclerView. Chaque ligne comporte un bouton de lecture, une vue texte et une barre de progression. Lorsque vous cliquez sur le bouton de lecture, vous devez lire l’audio de ma carte SD et que vous progressiez. Le problème est que lorsque je fais défiler la liste de recyclage, changez la barre de progression dans la rangée suivante. Lorsque je fais défiler la 6ème, la barre de recherche de 6ème rang change soudainement.

public class ListAdapter extends RecyclerView.Adapter { private List stethitems; public Context mContext; public Activity activity; public Handler mHandler; static MediaPlayer mPlayer; static Timer mTimer; public ListAdapter(Activity activity,Context mContext,List 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_Atsortingbute().replaceAll(" ","").equals("")){ myViewHolder.stethdoctorname.setText(dataItem.getunit()); } else { myViewHolder.stethdoctorname.setText(dataItem.getPatient_Atsortingbute()); } 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 Ssortingng downloadpath, final NumberProgressBar progressplay) { new AsyncTask() { 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 list = new ArrayList(); 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); }} 

S’il vous plaît essayer ceci

  1. Si vous utilisez ListView – remplacez les méthodes suivantes.

     @Override public int getViewTypeCount() { return getCount(); } @Override public int getItemViewType(int position) { return position; } 
  2. Si vous utilisez RecycyclerView – ne remplacez que la méthode getItemViewType() .

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

Comme son nom l’indique, les vues d’un RecyclerView sont recyclées au fur et à mesure que vous faites défiler. Cela signifie que vous devez conserver l’état de chaque élément de votre modèle de sauvegarde, qui dans ce cas serait un Historyitem , et le restaurer dans votre onBindViewHolder .

1) Créez la position, max et toutes les autres variables dont vous avez besoin pour enregistrer l’état du ProgressBar dans votre modèle.

2) Définissez l’état de votre ProgressBar fonction des données de votre modèle de sauvegarde; sur clic, transmettez la position de l’élément à vos méthodes 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) Mettez à jour la barre de progression en mettant à jour le modèle de support et en notifiant qu’il a été modifié.

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

Ajouter setHasStableIds(true); Dans votre constructeur d’adaptateur, remplacez ces deux méthodes dans l’adaptateur.

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

Placez recylerView dans une NestedScroll View dans votre XML et ajoutez la propriété nestedScrollingEnabled = false .

Et sur votre adaptateur onBindViewHolder ajoutez cette ligne

 final MyViewHolder viewHolder = (MyViewHolder)holder; 

Utilisez cet object viewHolder avec vos vues pour setText ou effectuer tout type d’événement de clic.

par exemple viewHolder.txtSubject.setText("Example");

J’ai eu le même problème en manipulant beaucoup de données, cela fonctionne avec 5 car il rend les cinq éléments visibles à l’écran mais cela donne plus d’éléments. La chose est ..

Parfois, RecyclerView et listView ignorent simplement les données de remplissage. Dans le cas où la fonction de liaison RecyclerView est ignorée pendant le défilement, mais lorsque vous essayez de déboguer l’adaptateur recyclerView, cela fonctionnera correctement car elle sera appelée à chaque fois onBind . Vers 20 min -30 min, ils vous expliqueront que vous ne pouvez jamais supposer que getView par position sera appelé à chaque fois.

alors, je vais suggérer d’utiliser

RecyclerView DataBinder créé par satorufujiwara.

ou

RecyclerView MultipleViewTypes Binder créé par yqritc.

Ce sont d’autres liants disponibles si vous trouvez ceux qui sont faciles à travailler.

C’est la manière de traiter les types MultipleView ou si vous utilisez une grande quantité de données. Ces reliures peuvent vous aider à lire attentivement la documentation qui résoudra le problème, paix !!

Cette ligne change la progression à 0 sur le défilement

 myViewHolder.progressplay.setProgress(0); 

Enregistrez son état quelque part puis chargez-le sur cette même ligne.

Pourquoi ne pas essayer comme ça,

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

essaye ça

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

voir aussi

C’est le comportement attendu de recyclerView. Puisque la vue est recyclée, vos éléments peuvent apparaître dans des vues aléatoires. Pour surmonter cela, vous devez spécifier quel élément est placé dans quel type de vue par vous-même. Cette information peut être conservée dans un SparseBooleanArray. Ce que vous pouvez faire est de créer un SparseBooleanArray dans votre adaptateur comme ceci

 SparseBooleanArray selectedItems = new SparseBooleanArray(); 

chaque fois que votre vue change, faites:

 selectedItems.put(viewItemIndex,true); 

Maintenant dans votre onBindViewHolder faire

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

Ceci est la base pour résoudre votre problème. Vous pouvez ajuster cette logique à tout type de problème similaire dans recyclerView.