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

时间:2018-05-30 21:47:16

标签: android android-recyclerview android-asynctask google-cloud-firestore android-livedata

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的适配器类。当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$3.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$1.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$2.call(AsyncTask.java:304)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.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) 

2 个答案:

答案 0 :(得分:1)

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

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

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

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

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

此外,您可能同时运行多个AsyncTasks,这可能会抛出ConcurrentModificationException,因此您应该使用lock同步列表上的操作,以便一次只能有一个线程修改列表。将此同步块添加到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;
    }
}

答案 1 :(得分:1)

我认为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

希望这有帮助