执行异步操作时 RecyclerView 不显示数据

RecyclerView not displaying data when Asynchronous operations performed

public class ProfileSearchRecyclerAdapter extends RecyclerView.Adapter<ProfileSearchRecyclerAdapter.ViewHolder>{

private static List<ProfileSearchResult> profileList = new ArrayList<>();
private List<ProfileSearchResult> profileListNew = new ArrayList<>();
private Context context;public ProfileSearchRecyclerAdapter(Context context){
    this.context = context;
}
public void notifyChanges(List<ProfileSearchResult> changes){
    profileListNew.addAll(changes);
    AsyncTaskRunner taskRunner = new AsyncTaskRunner();
    taskRunner.execute();
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_result_profile_layout,parent,false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

    RequestOptions profilePictureRequest = new RequestOptions();
    profilePictureRequest.placeholder(R.drawable.index);
    holder.name.setText(profileList.get(position).getName());
    holder.tag.setText(profileList.get(position).getTagline());
    Glide.with(context)
        .applyDefaultRequestOptions(profilePictureRequest)
        .load(profileList.get(position).getProfilePictureUrl())
        .into(holder.thumbnail);
}

@Override
public int getItemCount() {
    return profileList.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {

    View view;
    public CircleImageView thumbnail;
    public TextView name;
    public TextView tag;

    public ViewHolder(View itemView) {
        super(itemView);
        view = itemView;

        name = view.findViewById(R.id.search_result_name);
        tag = view.findViewById(R.id.search_result_tagline);
        thumbnail = view.findViewById(R.id.search_result_thumbnail);
    }
}


private class AsyncTaskRunner extends AsyncTask<List<ProfileSearchResult>, Void, Void> {

    /**
     * This method compares profileSearchResultChanges with profileList to add new files,
     * remove deleted files and  modify files (remove old version of a file and add it's new version)
     * Asynchronously
     * @param lists
     * @return
     */
    @Override
    protected Void doInBackground(List<ProfileSearchResult>... lists) {

        Iterator<ProfileSearchResult> iter = profileList.iterator();
        while (iter.hasNext()) {
            ProfileSearchResult result = iter.next();

            if(false == profileListNew.contains(result)){
                profileList.remove(result);
            }
        }
        iter = profileListNew.iterator();
        while (iter.hasNext()) {
            ProfileSearchResult result = iter.next();

            if(false == profileList.contains(result)){
                profileList.add(result);
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        invalidate();
    }
}
public void invalidate(){
    notifyDataSetChanged();
}

}

这是我的 recyclerview 的适配器 class。当 Livedata 为查询快照注册更新时,我将文档传递给适配器。当我分配

profileList = changes;

在没有任何异步操作的notifyChanges()中,我的recyclerview显示数据。但是当我执行异步操作时,RecyclerView 是空的。可能是什么原因?提前致谢

05-30 18:27:07.813 13453-14405/com.sachintitus.instafy.instafy E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #5
Process: com.sachintitus.instafy.instafy, PID: 13453
java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask.done(AsyncTask.java:318)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:243)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)
 Caused by: java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at com.sachintitus.instafy.instafy.adapters.ProfileSearchRecyclerAdapter$AsyncTaskRunner.doInBackground(ProfileSearchRecyclerAdapter.java:96)
    at com.sachintitus.instafy.instafy.adapters.ProfileSearchRecyclerAdapter$AsyncTaskRunner.doInBackground(ProfileSearchRecyclerAdapter.java:82)
    at android.os.AsyncTask.call(AsyncTask.java:304)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:243) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
    at java.lang.Thread.run(Thread.java:761) 

不要从主线程以外的任何其他线程调用 notifyDataSetChanged()。只需从 doInBackground() 中删除对 invalidate() 的调用,然后将其添加到 onPostExecute()

@Override
protected void onPostExecute(Void aVoid) {
    Log.w("PROCESS EXECUTED", String.valueOf(profileList.size()));
    invalidate();
}

ArrayList 在迭代时不应修改。不要在 ArrayList 上使用 remove() 方法,而是在迭代器上使用 remove() 方法。

Iterator<ProfileSearchResult> iter = profileList.iterator();
while (iter.hasNext()) {
    ProfileSearchResult result = iter.next();

    if(false == profileListNew.contains(result)){
        iter.remove();
    }
}

另外,您可能 运行 多个 AsyncTasks 并发,这可能会抛出 ConcurrentModificationException,因此您应该使用锁来同步列表上的操作,以便一次只有一个线程可以修改列表。像这样

将此同步块添加到 AsyncTask 中的 doInBackground()
@Override
protected Void doInBackground(List<ProfileSearchResult>... lists) {
    synchronized (profileList) {
        Iterator<ProfileSearchResult> iter = profileList.iterator();
        while (iter.hasNext()) {
            ProfileSearchResult result = iter.next();

            if(false == profileListNew.contains(result)){
                iter.remove();
            }
        }
        iter = profileListNew.iterator();
        while (iter.hasNext()) {
            ProfileSearchResult result = iter.next();

            if(false == profileList.contains(result)){
                profileList.add(result);
            }
        }
        return null;
    }
}

我认为 ConcurrentModificationException 的问题就在这里

Iterator<ProfileSearchResult> iter = profileList.iterator();
        while (iter.hasNext()) {
            ProfileSearchResult result = iter.next();

            if(false == profileListNew.contains(result)){
                profileList.remove(result); // <------- here <-------
            }
        }

在 java 中,如果您希望在使用其迭代器时从列表中删除一个元素,则必须使用迭代器的方法来执行此操作,否则将面临 ConcurrentModificationException

它主要是一种保护机制,可以确保迭代器不会在同一个列表节点上传递两次或跳过一个节点。 docs link

而不是profileList.remove(result);

尝试iter.remove()

检查这个example

希望对您有所帮助