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)
答案 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
希望这有帮助