ViewPager删除图片异常求助:残留显示与索引越界
解决ViewPager删除图片后的残留显示与索引越界问题
看起来你遇到了两个典型的ViewPager使用问题:删除图片后旧图残留,以及删除倒数第二张时触发IndexOutOfBoundsException。我来帮你一步步修复这些问题:
问题根源分析
- 图片残留:你提前在
onCreate中创建了所有PhotoView并加载图片,删除后只是移除了列表中的View,但ViewPager的复用机制会保留旧的View实例,导致残留显示;另外destroyItem方法的实现有误,没有正确移除对应的View。 - 索引越界:删除图片时只更新了Adapter的View列表,没有同步更新原始的图片路径列表
list,同时删除后没有调整ViewPager的当前位置,导致后续操作访问了无效的索引。
修复方案与代码修改
1. 重构ImagePagerAdapter,动态加载图片
我们把Adapter改为持有图片路径列表,而不是提前创建好的PhotoView列表,这样每次创建页面时都会动态生成View并加载正确的图片:
static class ImagePagerAdapter extends PagerAdapter { private Context mContext; private List<String> mImagePaths; public ImagePagerAdapter(Context context, List<String> imagePaths) { mContext = context; mImagePaths = imagePaths; } @Override public Object instantiateItem(ViewGroup container, int position) { PhotoView photoView = new PhotoView(mContext); photoView.setZoomable(true); // 加载当前位置的图片 Glide.with(mContext) .load(new File(mImagePaths.get(position))) .into(photoView); container.addView(photoView); return photoView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { // 直接移除传入的View对象,避免position索引错误 container.removeView((View) object); // 清理Glide缓存,避免旧图残留 Glide.with(mContext).clear((View) object); } @Override public int getCount() { return mImagePaths.size(); } void remove(int pos) { mImagePaths.remove(pos); notifyDataSetChanged(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } @Override public boolean isViewFromObject(View view, Object o) { return view == o; } }
2. 修改ImageViewer的初始化与删除逻辑
去掉提前创建photoViewList的代码,同步更新原始列表,并处理删除后的ViewPager位置:
public class ImageViewer extends AppCompatActivity { public int position; private ArrayList<String> list; private HackyViewPager pager; private ImagePagerAdapter ipa; private HelperMethods helperMethods; private static boolean sendResult = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.img); sendResult = false; helperMethods = new HelperMethods(ImageViewer.this); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().hide(); Intent i = getIntent(); position = i.getExtras().getInt("position"); list = i.getStringArrayListExtra("list"); pager = (HackyViewPager) findViewById(R.id.pager); // 直接传入图片路径列表给Adapter ipa = new ImagePagerAdapter(this, list); pager.setAdapter(ipa); pager.setCurrentItem(position); FloatingActionButton dlt = (FloatingActionButton) findViewById(R.id.dlt); dlt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(ImageViewer.this); builder.setMessage("Sure to Delete this Image?") .setNegativeButton("Nope", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .setPositiveButton("Delete", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int currentPos = pager.getCurrentItem(); // 1. 删除文件 getFilePos(currentPos).delete(); // 2. 同步更新原始列表和Adapter ipa.remove(currentPos); // 3. 调整ViewPager当前位置,避免索引越界 if (currentPos >= ipa.getCount()) { // 如果删除的是最后一项,跳转到新的最后一项 pager.setCurrentItem(ipa.getCount() - 1); } else { // 否则保持当前位置(因为删除当前项后,后面的项会前移) pager.setCurrentItem(currentPos); } Toast.makeText(ImageViewer.this, "Image Deleted", Toast.LENGTH_SHORT).show(); } }); builder.create().show(); } }); } // 修改getFilePos方法,传入当前位置,避免访问无效索引 public File getFilePos(int pos) { return new File(list.get(pos)); } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case android.R.id.home: onBackPressed(); break; } return true; } }
关键修复点说明
- 动态创建View:每次
instantiateItem都会生成新的PhotoView并加载对应路径的图片,彻底避免旧View的残留。 - 正确的destroyItem:直接移除传入的View对象,不会因为列表变化导致索引错误。
- 同步更新列表:删除时同时更新原始路径列表和Adapter,确保后续操作不会访问无效索引。
- 位置调整:删除后检查当前位置是否超出新的列表长度,及时调整,避免
IndexOutOfBoundsException。 - Glide缓存清理:在
destroyItem中清理对应View的Glide缓存,防止旧图残留。
这样修改后,你遇到的两个问题应该都能解决了。
内容的提问来源于stack exchange,提问作者darshan
相关产品推荐
相关产品推荐

