Android:使用AsyncTask删除文件时出现索引错误

时间:2015-01-20 11:20:05

标签: android android-adapter

我已经建立了一个图库,可以选择多个项目并删除。我使用自定义GridView将图片加载到BaseAdapter,同时删除我正在使用AsyncTask。但是如果尝试删除多个项目,则会使数组超出绑定异常。

java.lang.IndexOutOfBoundsException: Invalid index x, size is x
            at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
            at java.util.ArrayList.get(ArrayList.java:308)
            at com.android.Example.Adapters.ImageAdapter.getView(ImageAdapter.java:94)

只有当我使用AsynTask时才会出现此错误,如果我在主线程中执行此操作,则删除工作正常。

我不知道我的ArrayList何时出界。

这是我的自定义BaseAdapter

public class ImageAdapter extends BaseAdapter {
 private com.nostra13.universalimageloader.core.ImageLoader imageLoader;
 private Context mContext;
 private int displayWidth;
 private int imageWidth;
 private ArrayList<String> f = new ArrayList<String>();// list of file paths

 public ImageAdapter(Context c, ArrayList<String> f) {
    mContext = c;
    this.f=f;
    imageLoader = ImageLoader.getInstance();
    imageLoader.init(ImageLoaderConfiguration.createDefault(mContext));
    DisplayMetrics metrics = new DisplayMetrics();
    ((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(metrics);
    displayWidth = metrics.widthPixels;
    imageWidth=(displayWidth/3);
   }
  @Override
  public int getCount() {
    return this.f.size();
   }

  @Override
  public Object getItem(int position) {
    return this.f.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    final ImageView imageView;
    if (convertView == null) {
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new GridView.LayoutParams(imageWidth,imageWidth));
        imageView.setPadding(Utils.dpToPx(2), Utils.dpToPx(2), Utils.dpToPx(2), Utils.dpToPx(2));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setCropToPadding(true);
        imageView.setBackground(mContext.getResources().getDrawable(R.drawable.gridview_selector));
    } else {
        imageView = (ImageView) convertView;
    }
    //imageView.setAdjustViewBounds(true);
    imageLoader.displayImage("file:///"+this.f.get(position),imageView,); //This is line number 94
    return imageView;
}


}

这就是我要删除的方式。

  @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
      ArrayList<Uri> imageUris = new ArrayList<Uri>();
      SparseBooleanArray checked = gridView.getCheckedItemPositions();
      int checkedItemCount = gridView.getCheckedItemCount();
          switch (item.getItemId()) {
              case R.id.delete:
                   new DeleteAsync(checked, checkedItemCount).execute();
                   return true; 

这是我的AsyncTask

 private class DeleteAsync extends AsyncTask<Void, Void, Void> {
    SparseBooleanArray _checked;
    int _checkedItemCount;

    private DeleteAsync(SparseBooleanArray _checked, int _checkedItemCount) {
        this._checked = _checked;
        this._checkedItemCount = _checkedItemCount;
    }


 @Override
    protected Void doInBackground(Void... params) {
        for (int i = (_checkedItemCount - 1); i >= 0; i--) {
            if (_checked.valueAt(i)) {

                File file = new File(files.get(_checked.keyAt(i)));
                if (file.delete()) {
                    MediaScannerConnection.scanFile(getActivity(), new String[]{file.toString()}, null, null);
                    files.remove(_checked.keyAt(i));
                } else
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(rootView.getContext(), getResources().getString(R.string.delete_error), Toast.LENGTH_SHORT).show();
                        }
                    });
            }
        }

    }

    @Override
    protected void onPostExecute(Void void) {
        super.onPostExecute(void);
        imageAdapter.notifyDataSetChanged();
        progress.setVisibility(View.INVISIBLE);
    }
}

adapter设为GridView

   ArrayList<String> files=getListOfImagFiles();
   imageAdapter= new ImageAdapter(rootView.getContext(), files);
   gridView.setAdapter(imageAdapter);

5 个答案:

答案 0 :(得分:0)

删除前检查数组的大小。 这样的事情可能有用。

 if(items.size())>0
for (int i = _checkedItemCount; i > 0; i--) 
{

//do your stuff
}

答案 1 :(得分:0)

这是gridview适配器的getView中的常见问题。为了安全起见,我这样做了。

在getView()

中进行条件检查
if(position<this.f.size()) 
{
     imageLoader.displayImage("file:///"+this.f.get(position),imageView,); //This is line number 94
}
else
{
   //Display some default img or error img.
}

建议:

不要根据项目的位置删除数组项。根据项目模型对象删除。

遵循MVC指南。

答案 2 :(得分:0)

目前它的问题是

  1. 当您开始时,文件列表中共有10个项目。因此,索引将为0-9,并且您的for循环将针对此索引范围运行。
  2. 现在当您从文件arraylist中删除条目时,您的计数会减1,即它变为现在您的索引范围将为0-8。
  3. 因此,当你继续从文件中删除项目arraylist这行代码

    imageLoader.displayImage( “文件:///” + this.f.get(位置),ImageView的,);

  4. baseadapter内部将松开该位置。

    所以你有两个选择:

    1. 不要从文件中删除arraylist只是跟踪文件名,在onpostexecute中删除文件arraylist中的那些项目,并在你的baseadapter上使用notifydatasetchanged。
    2. 从文件arraylist中删除项目但在每次删除时使用onprogressupdate在你的baseadapter上调用notifydatasetchanged。

答案 3 :(得分:0)

奇怪的是,在加载图片之前,我只是安全地解决了我的问题。

 if(position<getCount())
     imageLoader.displayImage("file:///"+this.f.get(position),imageView,options);

我不接受我的回答,因为我认为这不是解决这个问题的完美解决方案,而且我也不知道为什么只有在我使用AsyncTask

时才会发生这种情况

答案 4 :(得分:0)

再次使用setAdapter而不是NotifyDataSetChanged,它将重新加载列表并且位置将是正确的。