Reputation: 453
On my RecyclerView.Adapter I submit a thread to a threadpoolexecutor from onBindViewHolder() to get previews of pdf files that my RecyclerView shows to the user.
After that thread does its thing, it should call notifyItemChanged().
The problem is, when the main thread calls something like notifyDataSetChanged() and and another thread tries to call notifyItemChanged(), the RecyclerView breaks (it will show the previous dataset until you scroll by any height, and many more weird stuff).
What should I use to fix the issues?
Here is my adapter (I removed all the non-relevant code):
public class listAdapter extends RecyclerView.Adapter<listAdapter.ViewHolder> {
rejectionHandler rejectionHandler = new rejectionHandler();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
ThreadPoolExecutor executorPool = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
2000,
10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors()),
threadFactory, rejectionHandler
);
@SuppressLint("NotifyDataSetChanged")
public void updateAll(){
notifyDataSetChanged();
}
public listAdapter(Context context, FileViewerModel FVM, listType clType)
{Not relevant}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
//Removed non-relevant code
else if(!file.previewIsOnTheWay) switch (Utilities.getExtension(fileName)) {
case ".pdf":
file.previewIsOnTheWay = true;
executorPool.submit(new previewThread(file, this, FVM));
break;
//I removed other cases because it wasn't relevant.
}
}
@NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{}
}
And here is my previewThread:
public class previewThread implements Runnable {
public previewThread(fileItem fileItem, listAdapter adapter, FileViewerModel fileViewerModel){
this.filePath= fileItem.getPath();
this.fileItem= fileItem;
this.adapter = adapter;
this.fvm = fileViewerModel;
}
@Override
public void run() {
switch (Utilities.getExtension(Objects.requireNonNull(filePath))) {
case ".pdf":
processPDF();
break;
default:
fileItem.previewResource = R.drawable.icon_preview; //TODO find document icon
}
if (Thread.interrupted()) return;
if (fvm.fileList.getValue().contains(fileItem)){
adapter.notifyItemChanged(fvm.fileList.getValue().indexOf(fileItem));
}
//I just need to call this line of code without breaking other stuff :(
}
private void processPDF() {Gives the fileItem a bitmap}
}
Upvotes: 0
Views: 1113
Reputation: 453
Replace
if (fvm.fileList.getValue().contains(fileItem)){
adapter.notifyItemChanged(fvm.fileList.getValue().indexOf(fileItem));
}
with
if (fvm.fileList.getValue().contains(fileItem)){
new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message inputMessage) {
adapter.notifyItemChanged(fvm.fileList.getValue().indexOf(fileItem));
}
}.sendEmptyMessage(1);
}
Upvotes: 0
Reputation: 100
The link below goes into detail a background thread communicating with UI(mainThread).
https://developer.android.com/guide/background/threading#communicating-with-the-main-thread
Upvotes: 1