I have a RecyclerView. In it, the items have a standard layout - one TextView and one ProgressBar. Items are added to the recyclerview at runtime. Whenever an Item is added, an AsyncTask is started which updates the ProgressBar. The AsynTask holds a reference to the ProgressBar object from the RecyclerView Adapter. The problem occurs when there are too many items in the recycler view.
I know the RecyclerView recycles any old views and thus want a way around that atleast for the progressbars.
What would be the ideal way to implement this?
Following 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();
}
Also, I'm adding items to the RecyclerView using notifydatasetchanged.
4
A little late, but I found a way to get it working.
My recyclerview contains a large number viewholders and only one of the viewholders have a progress bar. I have an sqlite database in which I maintain identifiers which I use to sync between my service and activity (to identify which views in the recyclerview need updating).
Depending on your implementation, you will have to find a way to identify which broadcast event corresponds to which adapter item. I have given a simplified version of what I have done below.
Model for 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 recyclerview 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 Activity which implements populates the view, create a static instance of itself and pass it to the BroadcastReceiver. It took me quite a while to figure out that the static instance is required, otherwise the view doesn't get changed even though 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.