这个问题经常出现在我的项目中,但我找不到原因。请给我一些建议。
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:20
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:20
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java)
at android.support.v7.widget.GapWorker.add(GapWorker.java)
postFromTraversal(GapWorker.java)
buildTaskList(GapWorker.java)
isPrefetchPositionAttached(GapWorker.java)
prefetchPositionWithDeadline(GapWorker.java)
prefetchInnerRecyclerViewWithDeadline(GapWorker.java)
flushTaskWithDeadline(GapWorker.java)
prefetch(GapWorker.java)
at android.support.v7.widget.GapWorker.add(GapWorker.java)
postFromTraversal(GapWorker.java)
buildTaskList(GapWorker.java)
isPrefetchPositionAttached(GapWorker.java)
prefetchPositionWithDeadline(GapWorker.java)
prefetchInnerRecyclerViewWithDeadline(GapWorker.java)
flushTaskWithDeadline(GapWorker.java)
prefetch(GapWorker.java)
at android.support.v7.widget.GapWorker.remove(GapWorker.java)
flushTasksWithDeadline(GapWorker.java)
at android.support.v7.widget.GapWorker.add(GapWorker.java)
postFromTraversal(GapWorker.java)
buildTaskList(GapWorker.java)
isPrefetchPositionAttached(GapWorker.java)
prefetchPositionWithDeadline(GapWorker.java)
prefetchInnerRecyclerViewWithDeadline(GapWorker.java)
flushTaskWithDeadline(GapWorker.java)
prefetch(GapWorker.java)
at android.support.v7.widget.GapWorker.run(GapWorker.java)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5896)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)
代码。
public class DuoBeiClassIntermediary implements IRecyclerViewIntermediary {
private List<ClassRoom> mClassRooms;
private Context context;
private Bus mBus;
private String isExpired;
private String courseName;
public DuoBeiClassIntermediary(Context context, List<ClassRoom> classRooms, String isExpired, String courseName) {
mClassRooms = classRooms;
this.context = context;
this.isExpired = isExpired;
this.courseName = courseName;
mBus = AppContext.getInstance().getBus();
mBus.register(this);
}
@Override
public int getItemCount() {
return mClassRooms.size();
}
@Override
public Object getItem(int position) {
return mClassRooms.get(position);
}
@Override
public RecyclerView.ViewHolder getViewHolder(ViewGroup viewGroup, int type) {
View view = LayoutInflater.from(context).inflate(R.layout.item_duobei_class, viewGroup, false);
return new ClassViewHolder(view);
}
@Override
public int getItemViewType(int position) {
return 0;
}
@Override
public void populateViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
final ClassRoom classRoom = mClassRooms.get(position);
((ClassViewHolder) viewHolder).tvClassNo.setText(position + 1 + "");
((ClassViewHolder) viewHolder).tvClassName.setText(classRoom.getRoomTitle());
String date = DateUtil.dateToString(DateUtil.StringToDate(classRoom.getStartTime(), "yyyy-MM-dd HH:mm:ss"), "MM月dd日");
String startTime = DateUtil.dateToString(DateUtil.StringToDate(classRoom.getStartTime(), "yyyy-MM-dd HH:mm:ss"), "HH:mm");
String endTime = DateUtil.dateToString(DateUtil.StringToDate(classRoom.getEndTime(), "yyyy-MM-dd HH:mm:ss"), "HH:mm");
((ClassViewHolder) viewHolder).btnExercise.setText("课后练习");
if (!TextUtils.isEmpty(classRoom.getDownloadVideoDuration())) {
if (classRoom.getDownloadVideoDuration().contains("'")) {
((ClassViewHolder) viewHolder).tvClassTime.setText(classRoom.getDownloadVideoDuration());
} else {
((ClassViewHolder) viewHolder).tvClassTime.setText(classRoom.getDownloadVideoDuration() + "分钟");
}
} else {
((ClassViewHolder) viewHolder).tvClassTime.setText(date + " " + startTime + "-" + endTime);
}
if (classRoom.getHasExercise() == 0) {
((ClassViewHolder) viewHolder).btnExercise.setVisibility(View.INVISIBLE);
} else {
((ClassViewHolder) viewHolder).btnExercise.setVisibility(View.VISIBLE);
}
if ("true".equals(classRoom.getShiting())) {
((ClassViewHolder) viewHolder).tvClassTime.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).downloadLayout.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).btnExercise.setVisibility(View.INVISIBLE);
((ClassViewHolder) viewHolder).btnClass.setText("立即观看");
} else {
((ClassViewHolder) viewHolder).tvClassTime.setVisibility(View.VISIBLE);
if (classRoom.getPayType() == 1) {
if (classRoom.getLiveType() == 0) {
((ClassViewHolder) viewHolder).btnExercise.setEnabled(true);
((ClassViewHolder) viewHolder).btnExercise.setBackgroundResource(R.drawable.btn_oval_88);
((ClassViewHolder) viewHolder).btnExercise.setTextColor(context.getResources().getColor(R.color.color_88));
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).btnClass.setText("未直播");
((ClassViewHolder) viewHolder).btnClass.setTextColor(context.getResources().getColor(R.color.color_88));
((ClassViewHolder) viewHolder).btnClass.setBackgroundResource(R.drawable.btn_oval_88);
((ClassViewHolder) viewHolder).btnClass.setEnabled(false);
((ClassViewHolder) viewHolder).classItem.setEnabled(false);
} else if (classRoom.getLiveType() == 1) {
((ClassViewHolder) viewHolder).btnExercise.setEnabled(true);
((ClassViewHolder) viewHolder).btnExercise.setBackgroundResource(R.drawable.course_status_blue_line_bg);
((ClassViewHolder) viewHolder).btnExercise.setTextColor(context.getResources().getColor(R.color.new_theme_color));
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).btnClass.setText("正在直播");
((ClassViewHolder) viewHolder).btnClass.setTextColor(context.getResources().getColor(R.color.white));
((ClassViewHolder) viewHolder).btnClass.setBackgroundResource(R.drawable.course_status_blue_bg);
((ClassViewHolder) viewHolder).btnClass.setEnabled(true);
((ClassViewHolder) viewHolder).classItem.setEnabled(true);
} else if (classRoom.getLiveType() == 2) {
((ClassViewHolder) viewHolder).btnExercise.setEnabled(true);
((ClassViewHolder) viewHolder).btnExercise.setBackgroundResource(R.drawable.course_status_blue_line_bg);
((ClassViewHolder) viewHolder).btnExercise.setTextColor(context.getResources().getColor(R.color.new_theme_color));
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.VISIBLE);
if (classRoom.getStatus() == Downloads.STATUS_SUCCESS) {
((ClassViewHolder) viewHolder).btnClass.setText("本地视频");
} else {
((ClassViewHolder) viewHolder).btnClass.setText("观看回放");
}
((ClassViewHolder) viewHolder).btnClass.setTextColor(context.getResources().getColor(R.color.new_theme_color));
((ClassViewHolder) viewHolder).btnClass.setBackgroundResource(R.drawable.course_status_blue_line_bg);
((ClassViewHolder) viewHolder).btnClass.setEnabled(true);
((ClassViewHolder) viewHolder).classItem.setEnabled(true);
} else if (classRoom.getLiveType() == 3) {
((ClassViewHolder) viewHolder).btnExercise.setEnabled(true);
((ClassViewHolder) viewHolder).btnExercise.setBackgroundResource(R.drawable.btn_oval_88);
((ClassViewHolder) viewHolder).btnExercise.setTextColor(context.getResources().getColor(R.color.color_88));
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).btnClass.setText("即将直播");
((ClassViewHolder) viewHolder).btnClass.setTextColor(context.getResources().getColor(R.color.new_theme_color));
((ClassViewHolder) viewHolder).btnClass.setBackgroundResource(R.drawable.course_status_blue_line_bg);
((ClassViewHolder) viewHolder).btnClass.setEnabled(true);
((ClassViewHolder) viewHolder).classItem.setEnabled(true);
}
} else {
((ClassViewHolder) viewHolder).classItem.setEnabled(false);
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).btnExercise.setVisibility(View.INVISIBLE);
}
}
if (classRoom.getListStatus() == Constants.DuobeiListStatus.DOWNLOAD) {
//下载view
((ClassViewHolder) viewHolder).btnClass.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).btnExercise.setVisibility(View.GONE);
if (!TextUtils.isEmpty(classRoom.getDownloadUrl())) {
Timber.e("status=" + classRoom.getStatus() + ",position=" + position);
Timber.e("url=" + classRoom.getDownloadUrl() + ",position=" + position);
//如果存在下载链接,才显示下载按钮
((ClassViewHolder) viewHolder).downloadLayout.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).totalSize.setText(Formatter.formatFileSize(context.getApplicationContext(), classRoom.getDownloadVideoSize()));
if (classRoom.getCurrentSize() > 0) {
((ClassViewHolder) viewHolder).currentSize.setText(Formatter.formatFileSize(context.getApplicationContext(), classRoom.getCurrentSize()) + "/");
}
if (classRoom.getStatus() == Downloads.STATUS_SUCCESS) {
//下载成功
((ClassViewHolder) viewHolder).error.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).progressStatus.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).speed.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setImageResource(R.drawable.icon_delete_status);
} else if (classRoom.getStatus() == Downloads.STATUS_WAIT
|| classRoom.getStatus() == Downloads.STATUS_WAITING_FOR_NETWORK
|| classRoom.getStatus() == Downloads.STATUS_WAITING_TO_RETRY) {
//等待状态
if (classRoom.getCurrentSize() > 0) {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.VISIBLE);
} else {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.GONE);
}
((ClassViewHolder) viewHolder).error.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).progressStatus.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).speed.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setImageResource(R.drawable.icon_wait_status);
} else if (classRoom.getStatus() == Downloads.STATUS_RUNNING) {
//正在下载 STATUS_RUNNING 和 CONTROLE_RUN的区别
((ClassViewHolder) viewHolder).error.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).progressStatus.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).speed.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.VISIBLE);
if (classRoom.getDownloadVideoSize() > 0) {
Timber.e("DuobeiClassIntermediary" + classRoom.getCurrentSize() * 100 / classRoom.getDownloadVideoSize());
((ClassViewHolder) viewHolder).progressStatus.setProgress((int) ((classRoom.getCurrentSize() * 100 / classRoom.getDownloadVideoSize())));
((ClassViewHolder) viewHolder).currentSize.setText(Formatter.formatFileSize(context.getApplicationContext(), classRoom.getCurrentSize()) + "/");
((ClassViewHolder) viewHolder).speed.setText(getNetSpeed());
}
} else if (classRoom.getStatus() == Downloads.STATUS_FILE_ERROR) {
((ClassViewHolder) viewHolder).error.setText("下载失败 内存不足");
((ClassViewHolder) viewHolder).error.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).downloadStatus.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).progressStatus.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).speed.setVisibility(View.GONE);
if (classRoom.getCurrentSize() > 0) {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.VISIBLE);
} else {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.GONE);
}
((ClassViewHolder) viewHolder).downloadStatus.setImageResource(R.drawable.icon_download_status);
} else {
//其他状态,都视为未下载状态
((ClassViewHolder) viewHolder).error.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).downloadStatus.setVisibility(View.VISIBLE);
((ClassViewHolder) viewHolder).progressStatus.setVisibility(View.GONE);
((ClassViewHolder) viewHolder).speed.setVisibility(View.GONE);
if (classRoom.getCurrentSize() > 0) {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.VISIBLE);
} else {
((ClassViewHolder) viewHolder).currentSize.setVisibility(View.GONE);
}
((ClassViewHolder) viewHolder).downloadStatus.setImageResource(R.drawable.icon_download_status);
}
} else {
((ClassViewHolder) viewHolder).downloadLayout.setVisibility(View.GONE);
}
} else if (classRoom.getListStatus() == Constants.DuobeiListStatus.NORMAL) {
//正常view
((ClassViewHolder) viewHolder).downloadLayout.setVisibility(View.GONE);
}
((ClassViewHolder) viewHolder).btnClass.setOnClickListener(v -> {
if (isExpired == null || !"1".equals(isExpired)) {
if ("true".equals(classRoom.getShiting())) {
//试听课
Intent intent = new Intent(context, DuobeiSampleClassActivity.class);
intent.putExtra("url", classRoom.getVideoUrl());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
intent.putExtra("classFlag", 1);
context.startActivity(intent);
} else {
//课程列表
if (classRoom.getStatus() == Downloads.STATUS_SUCCESS) {
//如果已经是本地视频的话
Intent intent = new Intent(context, DuobeiSampleClassActivity.class);
intent.putExtra("url", classRoom.getDownloadUrl());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
context.startActivity(intent);
} else {
Intent intent = new Intent(context, DuoBeiClassActivity.class);
intent.putExtra("roomId", classRoom.getRoomId());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
intent.putExtra("liveType", classRoom.getLiveType());
intent.putExtra("startTime", classRoom.getStartTime());
context.startActivity(intent);
}
}
} else {
Utils.showShortToast("课程已过期");
}
});
((ClassViewHolder) viewHolder).btnExercise.setOnClickListener(view -> {
if (isExpired == null || !"1".equals(isExpired)) {
if (classRoom.getLiveType() == 3 || classRoom.getLiveType() == 0) {
Utils.showShortToast("课程开始直播后才能进入练习~");
} else {
ExerciseListActivity.start(context, classRoom.getRoomId() + "", classRoom.getRoomTitle(), courseName);
StatisticsUtil.b511(context, courseName, classRoom.getRoomTitle());
}
} else {
Utils.showShortToast("课程已过期");
}
});
((ClassViewHolder) viewHolder).classItem.setOnClickListener(v -> {
if (isExpired == null || !"1".equals(isExpired)) {
if ("true".equals(classRoom.getShiting())) {
//试听课
Intent intent = new Intent(context, DuobeiSampleClassActivity.class);
intent.putExtra("url", classRoom.getVideoUrl());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
context.startActivity(intent);
} else {
//课程列表
if (classRoom.getStatus() == Downloads.STATUS_SUCCESS) {
//如果已经是本地视频的话
Intent intent = new Intent(context, DuobeiSampleClassActivity.class);
intent.putExtra("url", classRoom.getDownloadUrl());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
context.startActivity(intent);
} else {
Intent intent = new Intent(context, DuoBeiClassActivity.class);
intent.putExtra("roomId", classRoom.getRoomId());
intent.putExtra("roomTitle", classRoom.getRoomTitle());
intent.putExtra("liveType", classRoom.getLiveType());
intent.putExtra("startTime", classRoom.getStartTime());
context.startActivity(intent);
}
}
} else {
Utils.showShortToast("课程已过期");
}
});
((ClassViewHolder) viewHolder).downloadStatusLayout.setOnClickListener(v -> {
if (isExpired == null || !"1".equals(isExpired)) {
if (classRoom.getStatus() == Downloads.STATUS_SUCCESS) {
//下载成功
showDeleteDialog(classRoom.getDownloadUrl());
} else if (classRoom.getStatus() == Downloads.STATUS_WAIT) {
//等待状态从队列中移除url
List<ClassRoom> classRooms = new ArrayList<>();
classRooms.add(classRoom);
mBus.post(new RemoveDownloadUrlEvent(classRooms));
//更新状态
new Update(ClassRoom.class).set(ClassTable.COLUMN_STATUS + "=0")
.where(ClassTable.COLUMN_DOWNLOADURL + "=?", classRoom.getDownloadUrl())
.execute(true);
} else if (classRoom.getStatus() == Downloads.STATUS_RUNNING) {
//暂停
Utils.getDownloadManager().pauseDownload(classRoom.getDownloadId());
} else if (classRoom.getStatus() == Downloads.STATUS_PAUSED_BY_APP ||
classRoom.getStatus() == Downloads.STATUS_WAITING_TO_RETRY ||
classRoom.getStatus() == Downloads.STATUS_WAITING_FOR_NETWORK ||
classRoom.getStatus() == Downloads.STATUS_QUEUED_FOR_WIFI) {
//暂停重新开始下载
List<ClassRoom> classRooms = new ArrayList<>();
classRooms.add(classRoom);
mBus.post(new AddDownloadUrlEvent(classRooms));
} else {
//未下载
if (PreferenceUtils.build(context).isDownloadPathOnExternalSd()) {
//sdcard1下载
if (FileUtil.getSdAvaliableSize() > classRoom.getDownloadVideoSize()) {
List<ClassRoom> classRooms = new ArrayList<>();
classRooms.add(classRoom);
mBus.post(new AddDownloadUrlEvent(classRooms));
} else {
Utils.showShortToast("剩余空间不足,请清理存储空间或重设下载路径");
}
} else {
//sdcard2下载
if (FileUtil.getAnotherSdAvaliableSize(context) > classRoom.getDownloadVideoSize()) {
List<ClassRoom> classRooms = new ArrayList<>();
classRooms.add(classRoom);
mBus.post(new AddDownloadUrlEvent(classRooms));
} else {
Utils.showShortToast("剩余空间不足,请清理存储空间或重设下载路径");
}
}
}
} else {
Utils.showShortToast("课程已过期");
}
});
}
private long lastTotalRxBytes = 0;
private long lastTimeStamp = 0;
private String getNetSpeed() {
long nowTotalRxBytes = Utils.getTotalRxBytes(context);
long nowTimeStamp = System.currentTimeMillis();
long speed = 0;
if (nowTimeStamp - lastTimeStamp != 0) {
speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));
}
lastTimeStamp = nowTimeStamp;
lastTotalRxBytes = nowTotalRxBytes;
return String.valueOf(speed) + " kb/s";
}
public void unregister() {
mBus.unregister(this);
}
private void showDeleteDialog(final String downloadUrl) {
View view = View.inflate(context, R.layout.layout_wifi_switch_dialog, null);
TextView tip = (TextView) view.findViewById(R.id.tv_tip);
final TextView cancel = (TextView) view.findViewById(R.id.tv_cancel);
TextView commit = (TextView) view.findViewById(R.id.tv_commit);
tip.setText("确认删除");
final AlertDialog dialog = new AlertDialog.Builder(context)
.setView(view)
.setCancelable(true)
.show();
cancel.setOnClickListener(v -> dialog.cancel());
commit.setOnClickListener(v -> {
Utils.deleteFileByUrl(context, downloadUrl);
new Update(ClassRoom.class).set(ClassTable.COLUMN_STATUS + "=0,"
+ ClassTable.COLUMN_DOWNLOADID + "=0,"
+ ClassTable.COLUMN_CURRENTSIZE + "=0")
.where(ClassTable.COLUMN_DOWNLOADURL + "=?", downloadUrl)
.execute(true);
//如果有文件删除的话,那么就把因内存不足的状态置为0
new Update(ClassRoom.class).set(ClassTable.COLUMN_STATUS + "=0")
.where(ClassTable.COLUMN_STATUS + "=?", Downloads.STATUS_FILE_ERROR)
.execute(true);
dialog.cancel();
});
}
static class ClassViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.tv_class_no)
TextView tvClassNo;
@Bind(R.id.tv_class_name)
TextView tvClassName;
@Bind(R.id.tv_class_time)
TextView tvClassTime;
@Bind(R.id.btn_class)
TextView btnClass;
@Bind(R.id.item_class)
LinearLayout classItem;
@Bind(R.id.downloadStatus)
ImageView downloadStatus;
@Bind(R.id.iv_progress_status)
CircleProgressBar progressStatus;
@Bind(R.id.download_layout)
LinearLayout downloadLayout;
@Bind(R.id.tv_speed)
TextView speed;
@Bind(R.id.tv_currentsize)
TextView currentSize;
@Bind(R.id.tv_totalsize)
TextView totalSize;
@Bind(R.id.download_status_layout)
FrameLayout downloadStatusLayout;
@Bind(R.id.tv_error)
TextView error;
@Bind(R.id.btn_exercise)
TextView btnExercise;
public ClassViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}