recyclelerview中的回调会影响所有单元格

时间:2017-11-09 11:48:20

标签: android android-recyclerview

我在RecyclerView的每个单元格中都有一个按钮,用于启动下载网络调用。根据是否下载,下载或完成,单元格显示不同。

我的简化代码:

@Override public void onBindViewHolder(final CatalogViewHolder holder, int position) {


    final DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
        @Override public void started() {

            mainThreadHandler.post(new Runnable() {
                @Override public void run() {
                    holder.itemView.setBackground(//color1
                }
            });
        }

        @Override public void finished() {
            mainThreadHandler.post(new Runnable() {
                @Override public void run() {
                    holder.itemView.setBackground(//color 2
                }
            });
        }

        @Override public void error(Exception e) {
            mainThreadHandler.post(new Runnable() {
                @Override public void run() {
                    holder.itemView.setBackground(//color 3
                }
            });
        }
    };


    holder.button1.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View view) {
            assyncCall(statusCallback);
        }
    });


}

我第一次在一个牢房里掏钱,一切正常。如果我在另一个单元格的下载按钮上,它们都会更新。

我理解这是由于回收再利用回收细胞,但我无法弄清楚如何做得更好。

谢谢!

我的完整适配器:

public class CatalogRecyclerAdapter extends RecyclerView.Adapter<CatalogViewHolder> {

    public static final String TAG = "CatalogRecyclerAdapter";

    private final LayoutInflater inflater;
    private final DownloadCenter downloadCenter;
    private final ListInterface.FlowController flowController;
    private final ResourcesStringRepository resourcesStringRepository;
    private final ImageManagerFactory imageManagerFactory;
    private final Handler mainThreadHandler;

    public CatalogRecyclerAdapter(LayoutInflater inflater, ListInterface.FlowController flowController,
            DownloadCenter downloadCenter, ResourcesStringRepository resourcesStringRepository,
            ImageManagerFactory imageManagerFactory, Handler mainThreadHandler) {
        this.inflater = inflater;
        this.flowController = flowController;
        this.downloadCenter = downloadCenter;
        this.resourcesStringRepository = resourcesStringRepository;
        this.imageManagerFactory = imageManagerFactory;
        this.mainThreadHandler = mainThreadHandler;
    }

    private static final int TITLE = 0;
    private static final int USER = 2;
    private static final int PROGRAM = 3;
    private static final int COURSE = 4;
    private static final int GROUP = 5;
    private static final int MEDIA = 6;
    private static final int ERROR = 7;
    private static final int DEMO = 8;

    //The list of all elements
    private List<FilterableUser> users = new ArrayList<>();
    private List<CatalogProgram> programs = new ArrayList<>();
    private List<CatalogProgram> demos = new ArrayList<>();
    private List<CatalogCourse> courses = new ArrayList<>();
    private List<FilterableGroup> groups = new ArrayList<>();
    private List<CatalogMedia> medias = new ArrayList<>();

    //The list that will be displayed after filtering and research.
    List<Object> displayedList = new ArrayList<>();

    static final String TITLES[] = new String[10];

    static {
        Context ctx = M360Application.getContext();
        TITLES[USER] = ctx.getString(R.string.users);
        TITLES[PROGRAM] = ctx.getString(R.string.programs);
        TITLES[COURSE] = ctx.getString(R.string.courses);
        TITLES[GROUP] = ctx.getString(R.string.groups);
        TITLES[MEDIA] = ctx.getString(R.string.documents);
        TITLES[DEMO] = ctx.getString(R.string.programs_demo);
    }

    private String searchString;

    @Override public int getItemViewType(int position) {
        if (displayedList.get(position) instanceof String) {
            return TITLE;
        } else if (displayedList.get(position) instanceof FilterableUser) {
            return USER;
        } else if (displayedList.get(position) instanceof CatalogProgramDemo) {
            return DEMO;
        } else if (displayedList.get(position) instanceof CatalogProgram) {
            return PROGRAM;
        } else if (displayedList.get(position) instanceof CatalogCourse) {
            return COURSE;
        } else if (displayedList.get(position) instanceof FilterableGroup) {
            return GROUP;
        } else if (displayedList.get(position) instanceof CatalogMedia) {
            return MEDIA;
        } else if (displayedList.get(position) instanceof CatalogError) {
            return ERROR;
        } else {
            throw new ClassCastException(
                    "this adapter's displayedList is corrupted" + displayedList.get(position).toString());
        }
    }

    public void setData(List<Filterable> data, String searchedString) {
        searchString = searchedString;
        setData(data);
    }

    private void setData(List<Filterable> data) {

        LogDev.i(TAG, "setting data size: " + data.size());

        groups.clear();
        users.clear();
        programs.clear();
        demos.clear();
        courses.clear();
        medias.clear();

        for (Filterable element : data) {
            if (element instanceof CatalogCourse) {
                courses.add((CatalogCourse) element);
            } else if (element instanceof FilterableUser) {
                users.add((FilterableUser) element);
            } else if (element instanceof CatalogProgramDemo) {
                demos.add((CatalogProgramDemo) element);
            } else if (element instanceof CatalogProgram) {
                programs.add((CatalogProgram) element);
            } else if (element instanceof FilterableGroup) {
                groups.add((FilterableGroup) element);
            } else if (element instanceof CatalogMedia) {
                medias.add((CatalogMedia) element);
            }
        }

        constructDataSet();
    }

    private void constructDataSet() {
        displayedList.clear();

        if (!demos.isEmpty()) {
            displayedList.add(TITLES[DEMO]);
            displayedList.addAll(demos);
        }

        if (!programs.isEmpty()) {
            displayedList.add(TITLES[PROGRAM]);
            displayedList.addAll(programs);
        }

        if (!courses.isEmpty()) {
            displayedList.add(TITLES[COURSE]);
            displayedList.addAll(courses);
        }

        if (!users.isEmpty()) {
            displayedList.add(TITLES[USER]);
            displayedList.addAll(users);
        }

        if (!groups.isEmpty()) {
            displayedList.add(TITLES[GROUP]);
            displayedList.addAll(groups);
        }

        if (!medias.isEmpty()) {
            displayedList.add(TITLES[MEDIA]);
            displayedList.addAll(medias);
        }

        if (displayedList.isEmpty()) {
            displayedList.add(new CatalogError());
        }

        LogDev.w(TAG, "displayedList.size() : " + displayedList.size());

        notifyDataSetChanged();
    }

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

        switch (viewType) {
            case TITLE:
                return new TitleViewHolder(inflater.inflate(R.layout.item_list_title_catalog, parent, false));
            case USER:
                return new UserViewHolder(inflater.inflate(R.layout.widget_user_small, parent, false));
            case PROGRAM:
            case DEMO:
                return new ProgramViewHolder(inflater.inflate(R.layout.widget_program_small, parent, false));
            case COURSE:
                return new CourseViewHolder(inflater.inflate(R.layout.widget_course_small, parent, false));
            case GROUP:
                return new GroupViewHolder(inflater.inflate(R.layout.widget_group_small, parent, false));
            case MEDIA:
                return new MediaViewHolder(inflater.inflate(R.layout.widget_media_small, parent, false));
            case ERROR:
                return new CatalogErrorViewHolder(inflater.inflate(R.layout.widget_noresult_small, parent, false));
            default:
                LogDev.e(TAG, "view type not supported");
                return null;
        }
    }

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

        Object displayedObject = displayedList.get(position);
        //holder.bind(displayedObject, errorDisplayInterface);

        if (holder instanceof TitleViewHolder && displayedObject instanceof String) {

            ((TitleViewHolder) holder).tv.setText((String) displayedObject);
        } else if (holder instanceof ProgramViewHolder && displayedObject instanceof CatalogProgram) {

            bindProgramViewHolder((ProgramViewHolder) holder, (CatalogProgram) displayedObject);
        } else if (holder instanceof CourseViewHolder && displayedObject instanceof CatalogCourse) {

            bindCourseViewHolder((CourseViewHolder) holder, (CatalogCourse) displayedObject);
        } else if (holder instanceof GroupViewHolder && displayedObject instanceof FilterableGroup) {

            bindGroupViewHolder((GroupViewHolder) holder, (FilterableGroup) displayedObject);
        } else if (holder instanceof UserViewHolder && displayedObject instanceof FilterableUser) {

            bindUserViewHolder((UserViewHolder) holder, (FilterableUser) displayedObject);
        } else if (holder instanceof MediaViewHolder && displayedObject instanceof CatalogMedia) {

            bindMediaViewHolder((MediaViewHolder) holder, (CatalogMedia) displayedObject);
        } else if (holder instanceof CatalogErrorViewHolder) {
            //No binding with any data
        } else {
            throw new ClassCastException(displayedObject.toString());
        }

        //Highlight
        if (searchString != null && !searchString.isEmpty())

        {
            TextViewHighlighter.highlight(holder, searchString);
        }
    }

    private void bindCourseViewHolder(final CourseViewHolder courseViewHolder, final CatalogCourse course) {
        courseViewHolder.name_textView.setText(course.name);
        courseViewHolder.viewNb_textView.setText(course.views != null ? course.views.toString() : "0");

        if (course.elementCount == null) {
            courseViewHolder.counterLinear.setVisibility(View.GONE);
        } else {
            courseViewHolder.counterLinear.setVisibility(View.VISIBLE);
            courseViewHolder.questionNb_textView.setText(
                    course.elementCount.questions != null ? course.elementCount.questions.toString() : "0");
            courseViewHolder.mediaNb_textView.setText(
                    course.elementCount.medias != null ? course.elementCount.medias.toString() : "0");
            courseViewHolder.sheetNb_textView.setText(
                    course.elementCount.sheets != null ? course.elementCount.sheets.toString() : "0");
        }

        imageManagerFactory.course(course.id).thumbnail(courseViewHolder.pic_imageView);
        //new CourseImageManager(course.id).load(courseViewHolder.pic_imageView);

        View.OnClickListener clickListener = new View.OnClickListener() {
            @Override public void onClick(View view) {
                flowController.routeToCourse(course.id);
            }
        };

        courseViewHolder.container.setOnClickListener(clickListener);

        if (course.canBeOffline) {

            courseViewHolder.downloadBlock.setVisibility(View.VISIBLE);

            DownloadState state = downloadCenter.getCourseStatus(course.id);

            LogDev.i(TAG, "can be offline " + state.name());

            if (state == DownloadState.DOWNLOADING) {
                updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADING);
            }

            if (state == DownloadState.TO_DOWNLOAD) {
                updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADABLE);
            }

            if (state == DownloadState.DOWNLOADED || state == DownloadState.DOWNLOADED_WITH_SHARED_MODE) {
                updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADED);
            } else {

                DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
                    @Override public void started() {

                        LogDev.i(TAG, "started");

                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADING);
                            }
                        });
                    }

                    @Override public void finished() {
                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADED);
                            }
                        });
                    }

                    @Override public void error(Exception e) {
                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                updateDownloadBlock(courseViewHolder, DownloadableStatus.ERROR);
                            }
                        });
                    }
                };

                downloadCenter.subscribe(course.id, statusCallback);
                courseViewHolder.downloadBlock.setOnClickListener(new View.OnClickListener()

                {
                    @Override public void onClick(View v) {
                        new Thread() {
                            @Override public void run() {
                                super.run();
                                try {
                                    downloadCenter.downloadCourse(course.id, null);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }.start();
                    }
                });
            }
        } else {
            LogDev.i(TAG, "can't be offline");
            courseViewHolder.downloadBlock.setVisibility(View.INVISIBLE);
        }
    }

    private void updateDownloadBlock(CourseViewHolder courseViewHolder, DownloadableStatus status) {

        if (status == null) return;

        courseViewHolder.downloadBlock.setVisibility(
                status.equals(DownloadableStatus.NOT_DOWNLOADABLE) ? View.GONE : View.VISIBLE);
        courseViewHolder.downloadImage.setVisibility(
                status.equals(DownloadableStatus.DOWNLOADABLE) ? View.VISIBLE : View.GONE);
        courseViewHolder.downloadProgress.setVisibility(
                status.equals(DownloadableStatus.DOWNLOADING) ? View.VISIBLE : View.GONE);
        courseViewHolder.downloadedImage.setVisibility(
                status.equals(DownloadableStatus.DOWNLOADED) ? View.VISIBLE : View.GONE);
        courseViewHolder.downloadErrImage.setVisibility(
                status.equals(DownloadableStatus.ERROR) ? View.VISIBLE : View.GONE);
    }

    private enum DownloadableStatus {
        NOT_DOWNLOADABLE, DOWNLOADABLE, DOWNLOADING, DOWNLOADED, ERROR
    }

    private void bindProgramViewHolder(ProgramViewHolder programViewHolder, final CatalogProgram program) {

        imageManagerFactory.program(program.id).thumbnail(programViewHolder.pic_imageView);
        //new ProgramImageManager(program.id).load(programViewHolder.pic_imageView);
        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override public void onClick(View view) {
                flowController.routeToProgram(program.id);
            }
        };

        programViewHolder.container.setOnClickListener(onClickListener);
        programViewHolder.pic_imageView.setOnClickListener(onClickListener);
        programViewHolder.title_textView.setText(program.name);
        programViewHolder.viewCount_textView.setText(program.views != null ? program.views.toString() : "0");
    }

    private void bindUserViewHolder(UserViewHolder userViewHolder, final FilterableUser user) {

        userViewHolder.name_textView.setText(user.name);
        userViewHolder.job_textView.setText(user.description);

        imageManagerFactory.user(user.id).thumbnail(userViewHolder.pic_imageView);
        //new UserImageManager(user.id).loadProfilePic(userViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(),
        //        true);

        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override public void onClick(View view) {
                flowController.routeToUser(user.id);
            }
        };

        userViewHolder.pic_imageView.setOnClickListener(onClickListener);
        userViewHolder.container.setOnClickListener(onClickListener);
    }

    private void bindMediaViewHolder(MediaViewHolder mediaViewHolder, final CatalogMedia media) {

        imageManagerFactory.media(media.id, media.type, media.extention).symbolOnThumbnail(mediaViewHolder.complex);
        //new MediaImageManager(media).load(mediaViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(), false);
        mediaViewHolder.title_textView.setText(media.title);
        mediaViewHolder.authorName_textView.setText(media.authorName);

        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override public void onClick(final View view) {
                flowController.routeToDocument(media.id);
            }
        };

        mediaViewHolder.complex.setOnClickListener(onClickListener);
        mediaViewHolder.container.setOnClickListener(onClickListener);
    }

    private void bindGroupViewHolder(GroupViewHolder groupViewHolder, final FilterableGroup group) {

        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override public void onClick(View view) {
                flowController.routeToGrouop(group.id);
            }
        };

        groupViewHolder.pic_imageView.setOnClickListener(onClickListener);
        groupViewHolder.container.setOnClickListener(onClickListener);

        groupViewHolder.name_textView.setText(group.name);
        String str = resourcesStringRepository.getQuantityString(R.plurals.catalog_group_stat_program,
                group.nbProgramsRunning, group.nbProgramsRunning);
        str += " - " + resourcesStringRepository.getQuantityString(R.plurals.catalog_group_stat_user, group.nbUser,
                group.nbUser);
        groupViewHolder.stats_textView.setText(str);

        imageManagerFactory.group(group.id).thumbnail(groupViewHolder.pic_imageView);
        //new GroupImageManager(group.id).load(groupViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(), true);
    }

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

2 个答案:

答案 0 :(得分:0)

它正在回收视图。因此,在单击按钮时,您必须存储其位置并相应地更改视图。

像这样

维护一个全局存储变量的位置
private int itemClicked=-1;

点击视图时,将位置存储到itemclicked

 holder.button1.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View view) {
        itemclicked=position;
        assyncCall(statusCallback);
    }
 });

然后在更新视图时检查位置是否与此相同

if(position==itemclicked){
    //show download for clicked view
}else{
    //show download stopped for other views
}

答案 1 :(得分:-1)

解决方案

正如Surender和Trickcy Solution建议的那样,我更新了呈现的数据,然后告诉适配器相应地更新单元格:

DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
                    @Override public void started() {

                        LogDev.i(TAG, "started");

                        course.downloadState = DownloadState.DOWNLOADING;

                        final int position = courseViewHolder.getAdapterPosition();
                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                notifyItemChanged(position);
                            }
                        });
                    }

                    @Override public void finished() {
                        course.downloadState = DownloadState.DOWNLOADED;

                        final int position = courseViewHolder.getAdapterPosition();
                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                notifyItemChanged(position);
                            }
                        });
                    }

                    @Override public void error(Exception e) {
                        course.downloadState = DownloadState.ERROR_WHILE_DOWNLOADING;

                        final int position = courseViewHolder.getAdapterPosition();
                        mainThreadHandler.post(new Runnable() {
                            @Override public void run() {
                                notifyItemChanged(position);
                            }
                        });
                    }
                };