簡體   English   中英

Android RecyclerView Adapter:如何實現 notifyItemChanged 線程安全?

[英]Android RecyclerView Adapter: how to implement notifyItemChanged thread safety?

在我的 RecyclerView.Adapter 上,我從 onBindViewHolder() 向 threadpoolexecutor 提交一個線程,以獲取我的 RecyclerView 向用戶顯示的 pdf 文件的預覽。

在那個線程完成它的事情之后,它應該調用 notifyItemChanged()。

問題是,當主線程調用諸如 notifyDataSetChanged() 之類的東西並且另一個線程嘗試調用 notifyItemChanged() 時,RecyclerView 會中斷(它會顯示先前的數據集,直到您滾動任意高度,以及更多奇怪的東西)。

我應該用什么來解決這些問題?

這是我的適配器(我刪除了所有不相關的代碼):

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

這是我的預覽線程:

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

下面的鏈接詳細介紹了與 UI(mainThread)通信的后台線程。

https://developer.android.com/guide/background/threading#communicating-with-the-main-thread

代替

if (fvm.fileList.getValue().contains(fileItem)){
   adapter.notifyItemChanged(fvm.fileList.getValue().indexOf(fileItem));
}

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM