Update ProgressBar in RecyclerView

I have a RecyclerView. Elements in it have a standard layout - one TextView and one ProgressBar. Elements are added to recyclerview at runtime. Whenever Item is added, AsyncTask is launched, which updates the ProgressBar. AsynTask contains a reference to the ProgressBar object from the RecyclerView adapter. The problem occurs when there are too many elements in the recycler.

I know that RecyclerView recycles any old views and thus wants it to be at least for progressive bars.

What would be the perfect way to implement this?

Below is an excerpt from the adapter

public class RecViewAdapter extends RecyclerView.Adapter<RecViewAdapter.ViewHolder> { Context mContext; List<String> mRunns; static ExecutorService mExec; static HashSet<Integer> mProcessed = new HashSet<>(); public RecViewAdapter(Context context, List<String> runns) { mContext = context; mRunns = runns; mExec = Executors.newFixedThreadPool(1); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.runnabel_item, viewGroup, false); ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.runnName.setText(mRunns.get(position)); if (!mProcessed.contains(position)) { new ProgressTask(holder.pBar, position).executeOnExecutor(mExec, null); mProcessed.add(position); } } @Override public int getItemCount() { return mRunns.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { TextView runnName; ProgressBar pBar; public ViewHolder(View view) { super(view); runnName = (TextView) view.findViewById(R.id.textView); pBar = (ProgressBar) view.findViewById(R.id.progressBar); pBar.setIndeterminate(false); pBar.setMax(100); pBar.setProgress(0); } } } 

In addition, I am adding items to the RecyclerView using notifydatasetchanged.

+10
android android-recyclerview
source share
2 answers

A little late, but I found a way to make it work.

My recyclerview contains a large number of viewers, and only one of the viewers has a progress bar. I have a sqlite database in which I maintain identifiers that I use to synchronize between my service and activity (to determine which views in recyclerview need to be updated).

Depending on your implementation, you will need to find a way to determine which translation event matches that adapter element. I gave a simplified version of what I did below.

Model for the progress bar:

 class ProgressModel{ String progressId; int progress = 0; } public int getProgress(){ return progress; } 

ViewHolder:

 public class ProgressViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; public ProgressViewHolder(View itemView) { mProgressBar = (ProgressBar) itemView.findViewById(R.id.mProgressBar); } public ProgressBar getProgressBar() { return mProgressBar; } } 

In the recycliewiew adapter,

 @Override public void onBindViewHolder(ProgressViewHolder holder, int position) { ProgressModel item = mData.get(position); int progress = item.getProgress(); if (progress > 0) { ProgressBar downloadProgress = holder.getProgressBar(); if (downloadProgress.isIndeterminate()) { downloadProgress.setIndeterminate(false); } downloadProgress.setProgress(progress); } } public void refresh(position, ProgressModel item){ mData.set(position, item); notifyItemChanged(position); } 

In the Office, which implements the filling of the view, create a static instance of yourself and pass it to BroadcastReceiver. It took me a while to figure out that a static instance is required, otherwise the view will not be changed, although I call notifyItemchanged ().

 public class MainActivity extends Activity{ private static MainActivity instance; private MyReceiver mReceiver; private MyAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); instance = this; mReceiver = new MyReceiver(instance); //TODO: Initialize adapter with data and set to recyclerview } public void update(Intent intent){ ProgressModel model = new ProgressModel (); //TODO: set progress detail from intent to model and get position from progressId instance.mAdapter.refresh(position,model); } private static class MyReceiver extends BroadcastReceiver { MainActivity activity; public DownloadReceiver(MainActivity activity) { this.activity = activity; } @Override public void onReceive(Context context, Intent intent) { //pass intent with progress details to activity activity.update(intent); } } } 

Hope this helps.

+4
source share

You can simply use the "findViewHolderForAdapterPosition" method to represent the recirculator and you will get a viewHolder object of this type, then insert this viewHolder into your adapter viewfinder so that you can directly access your widget views, (in this case, we turn to progressBar)

Below is sample code for Kotlin

  /** * update progress bar in recycler view * get viewHolder from position and progress bar from that viewHolder * we are rapidly updating progressbar so we did't use notify method as it always update whole row instead of only progress bar * @param position : position of list cell * @param progress : new progress value */ private fun updateDownloadProgressBar(position :Int, progress:Int) { val viewHolder = recyclerViewDownload.findViewHolderForAdapterPosition(position) (viewHolder as ViewHolderDownload).progressBarDownload.progress=progress } 
0
source share

All Articles