Подтвердить что ты не робот

ArrayIndexOutOfBoundsException при использовании ListAdapter

Я использую пользовательский ListAdapter для ListView. Я ничего не меняю динамически (количество просмотров, типы просмотров, включено/отключено, я читаю другие сообщения, но они что-то меняют из кода). Я должен сделать следующее, чтобы вызвать исключение. Прокрутите вниз до конца списка и после этого снова прокрутите список. В начале анимации прокрутки я получаю это исключение.

04-14 09:41:43.907: ERROR/AndroidRuntime(400): FATAL EXCEPTION: main
04-14 09:41:43.907: ERROR/AndroidRuntime(400): java.lang.ArrayIndexOutOfBoundsException
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:4540)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:3370)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.widget.AbsListView.onTouchEvent(AbsListView.java:2233)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.widget.ListView.onTouchEvent(ListView.java:3446)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.View.dispatchTouchEvent(View.java:3885)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.os.Looper.loop(Looper.java:123)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at android.app.ActivityThread.main(ActivityThread.java:3683)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at java.lang.reflect.Method.invokeNative(Native Method)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at java.lang.reflect.Method.invoke(Method.java:507)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
04-14 09:41:43.907: ERROR/AndroidRuntime(400):     at dalvik.system.NativeStart.main(Native Method)

Ниже приведена полная реализация.

public class CompanyDetailsAdapter implements ListAdapter {

  private Context context;
  private LayoutInflater inflater;

  private static final class ViewType {
    private static final int HEADER = 1;
    private static final int TEXT = 2;
    private static final int ADDRESS = 3;
    private static final int REVIEWS = 4;
    private static final int PRODUCTS = 5;
  }

  //all the cells in the order they appear
  private static final class ViewPositions {
    private static final int CompanyNameHeader = 0;
    private static final int CompanyName = 1;
    private static final int ContactHeader = 2;
    private static final int Phone = 3;
    private static final int Website = 4;
    private static final int AddressHeader = 5;
    private static final int Address = 6;
    private static final int DescriptionHeader = 7;
    private static final int Description = 8;
    private static final int ReviewsHeader = 9;
    private static final int Reviews = 10;
    private static final int ProductsHeader = 11;
    private static final int Products = 12;
  }

  //list of cells by types
  private static final int[] viewTypes = {
  ViewType.HEADER,      //0
  ViewType.TEXT,            //1
  ViewType.HEADER,      //2
  ViewType.TEXT,            //3
  ViewType.TEXT,            //4
  ViewType.HEADER,      //5
  ViewType.ADDRESS,     //6
  ViewType.HEADER,      //7
  ViewType.TEXT,            //8
  ViewType.HEADER,      //9
  ViewType.REVIEWS,     //10
  ViewType.HEADER,      //11
  ViewType.PRODUCTS     //12
  };

  //headers
  private static final int[] headerPositions = {
  ViewPositions.CompanyNameHeader,
  ViewPositions.ContactHeader,
  ViewPositions.AddressHeader,
  ViewPositions.DescriptionHeader,
  ViewPositions.ReviewsHeader,
  ViewPositions.ProductsHeader
  };

  //header resources for position where needed
  private static final int[] headerResources = {
  R.string.companyName,
  0,
  R.string.contact,
  0,
  0,
  R.string.address,
  0,
  R.string.description,
  0,
  R.string.reviews,
  0,
  R.string.products,
  0
  };

  //regular texts
  private static final int[] textPositions = {
  ViewPositions.CompanyName,
  ViewPositions.Phone,
  ViewPositions.Website,
  ViewPositions.Description,
  };

  public CompanyDetailsAdapter(Context context) {
    this.context = context;
    this.inflater = LayoutInflater.from(this.context);
  }

  public int getCount() {
    return viewTypes.length;
  }

  public Object getItem(int position) {
    return null;
  }

  public long getItemId(int position) {
    return position+1;
  }

  public int getItemViewType(int position) {
    return viewTypes[position];
  }

  public View getView(int position, View convertView, ViewGroup parent) {

    if (arrayContains(headerPositions, position)) {
      LinearLayout layout = null;
      TextView txtHeader = null;
      if (convertView == null) {
        layout = (LinearLayout)inflater.inflate(R.layout.header_listview,parent, false);
      } else {
        layout = (LinearLayout)convertView;
      }
      txtHeader = (TextView)layout.findViewById(R.id.txtHeader);
      String value = context.getText(headerResources[position]).toString();
      txtHeader.setText(value);
      return layout;
    } else if (arrayContains(textPositions, position)) {
      TextView txtText = null;
      LinearLayout layout = null;
      Company c = Company.getSelectedCompany();
      if (convertView == null) {
        layout = (LinearLayout)inflater.inflate(R.layout.default_text,parent, false);
      } else {
        layout = (LinearLayout)convertView;
      }
      txtText = (TextView)layout.findViewById(R.id.txtNormalText);
      switch (position) {
        case ViewPositions.CompanyName:
          txtText.setText(c.getName());
          break;
        case ViewPositions.Phone:
          txtText.setText(c.getPhone());
          break;
        case ViewPositions.Website:
          txtText.setText(c.getWebsiteString());
          break;
        case ViewPositions.Description:
          txtText.setText(c.getDescription());
          break;
      }
      return layout;
    } else {
      View v = null;
      //LinearLayout layout = null;
      Company company = Company.getSelectedCompany();
      switch (position) {
        case ViewPositions.Address:
          if (convertView == null)
            v = (LinearLayout)inflater.inflate(R.layout.adress, parent,false);
          else
            v = (LinearLayout)convertView;

          TextView txtAddress = (TextView)v.findViewById(R.id.txtAddress);
          txtAddress.setText(String.format("%s %s %s", company.getCity(),
                                           company.getStreet(), company.getPostalCode()));
          break;
        case ViewPositions.Products:
          if (convertView == null)
            v = (LinearLayout)inflater.inflate(R.layout.products, parent,false);
          else
            v = (LinearLayout)convertView;

          v = (LinearLayout)inflater.inflate(R.layout.products, parent,false);
          TextView txtNumProducts = (TextView)v.findViewById(R.id.txtNumProducts);
          txtNumProducts.setText(String.valueOf(company.getNrProducts()));
          break;
        case ViewPositions.Reviews:
          if (convertView == null)
            v = (LinearLayout)inflater.inflate(R.layout.reviews, parent,false);
          else
            v = (LinearLayout)convertView;

          v = (LinearLayout)inflater.inflate(R.layout.reviews, parent,false);
          TextView txtNumReviews = (TextView)v.findViewById(R.id.txtNumReviews);
          txtNumReviews.setText(String.valueOf(company.getNrReviews()));
          RatingBar rating = (RatingBar)v.findViewById(R.id.ratAvg);
          rating.setRating(company.getAvgRating());
          break;
      }
      return v;
    }
  }

  public int getViewTypeCount() {
    return 5;
  }

  public boolean hasStableIds() {
    return true;
  }

  public boolean isEmpty() {
    return false;
  }

  public void registerDataSetObserver(DataSetObserver arg0) {
  }

  public void unregisterDataSetObserver(DataSetObserver arg0) {
  }

  public boolean areAllItemsEnabled() {
    return false;
  }

  public boolean isEnabled(int position) {
    if (arrayContains(headerPositions, position)) return false;
    return true;
  }

  private Boolean arrayContains(int[] array, int element) {
    for (int i=0; i<array.length; i++) {
      if (array[i] == element) return true;
    }
    return false;
  }


}

Я подключил источники к библиотеке Android 2.3.3 из здесь. Я ничего не узнал, что трассировка стека не показала мне. Как вы все знаете, ListView перерабатывает виды. Существует коллекция, которая хранит эти переработанные виды. Когда представление исчезает, оно добавляется там (я думаю). Это происходит при at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:4540) Где-то здесь это дает мне исключение, что что-то выходит за пределы. У меня нет ни малейшего понятия, что. Но у меня нет терпения, чтобы отлаживать еще 1000 строк кода, поэтому я думаю, что сейчас буду использовать ScrollView.


Кажется, что эта строка: (AbsListView.class: 4540 mScrapViews[viewType].add(scrap); mScrapViews имеет тип private ArrayList<View>[] mScrapViews;. Это массив списков типа View. Я могу попытаться посмотреть viewType и scrap, но он говорит errors_during_evaluation. Вероятно, слишком тупой, чтобы оценить.

4b9b3361

Ответ 1

Нашел проблему. Просмотр типов должен был начинаться с 0, запуск начинается с 1.

Android использует типы просмотра, которые я предоставил для доступа к массиву по индексу где-нибудь. SomeArraySomewhere[myViewType] Размер этого массива, вероятно, равен количеству видов. Таким образом, это означает, что я должен начинать типы просмотров в 0.

Ответ 2

Измените это:

public int getViewTypeCount()
{
    return 2;
}

мне это помогло:

public int getViewTypeCount()
{
    return 3;
}

Объяснение:

Первоначально у меня было 2 типа вида, но позже в реализации я добавил третий. Я начал получать это исключение, потому что забыл обновить метод getViewTypeCount(), чтобы вернуть 3 вместо двух.

Надеюсь, это поможет кому-то:)

Ответ 3

Возможно, что position:

  • a: null
  • b: higher then the amount of headerResources?

В этой строке (getView):

String value = context.getText(headerResources[position]).toString();

Сначала научитесь отлаживать: вот хороший видеоурок

Ответ 4

Причина, скорее всего, потому, что метод getItemViewType возвращает неправильные значения! Каждая строка в списке - это один вид. В то время как scrooling getItemViewType достигает больше, чем Просмотр count.

Что делать? Как избежать проблемы?

Сначала определите представление (строку) в вашем списке, которое показано первым. Если прокрутка использует уравнение модулятора

@Override
public int getItemViewType(int position) {
    return choseType(position);//function to use modular equation
}
@Override
public int getViewTypeCount() {
    return 10;
}

В этом примере представлено десять представлений (10 строк).

private  int choseType(int position){
    if(position%10==0)
        return 0;
    else if(position%10==1)
        return 1;
    else if(position%10==2)
        return 2;
    else if(position%10==3)
        return 3;
    else if(position%10==4)
        return 4;
    else if(position%10==5)
        return 5;
    else if(position%10==6)
        return 6;
    else if(position%10==7)
        return 7;
    else if(position%10==8)
        return 8;
    else
        return 9;


}

Внимание!

Некоторые пользователи упомянули о другом вопросе о методе stackoverflow, который

public int getViewTypeCount() и public int getItemViewType (int position) fix, как Tooglebutton, автоматически активирует проверку состояния true на scrooling.. , что является большим неправильным. Если вы не хотите, чтобы автоматическая enbale на scrool просто делала

toogleButton.setChecked(false);

в методе переопределения getView.