我在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();
}
}
答案 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);
}
});
}
};