androidlistviewarraylistindexoutofboundsexceptiononitemclick

Android intermittent error onitemclick java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0


Can't figure this one out and I've searched quite a bit. Can't simulate the error on any of my test devices but happens occasionally to some of my users.

I have a custom listview adapter, 6 items are pulled from an online db and added to the list. I also add an additional static footer to the bottom of the list.

I understand the listview has nothing in it when this error occurs, it's 0 so the app can't get the position - due to pulling the string from the online db.

I have tried to cover this by having an if/else but still getting an indexoutofbounds error. on line:

if(mCategoryAdapter.getItem(position)!=null)

or

Category category = mCategoryAdapter.getItem(position);

My question is - I assume users are clicking in the list before it's completely populated? Any thoughts how to stop this?

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    //assigning XML view
    setContentView(R.layout.activity_category);

    //fill the list view from data from parse.com using custom CategoryAdapter
    mCategoryAdapter = new CategoryAdapter(this, new ArrayList<Category>());
    //assigning ListView to XML ListView
    mListView = (ListView)findViewById(R.id.category_list);
    mListView.setAdapter(mCategoryAdapter);
    customExercisesView = getLayoutInflater().inflate(R.layout.category_custom_exercises_row_item,mListView,false);

    //make items in list clickable
    mListView.setOnItemClickListener(this);
    //parse query to retrieve the categories
    getCategoryList();
}

public void getCategoryList()
{

    //parse query to pull all the current available exercises from the db
    ParseQuery<Category> query = ParseQuery.getQuery(Category.class).fromLocalDatastore();
    //call to parse.com to start the query
    query.findInBackground(new FindCallback<Category>() {
        @Override
        public void done(List<Category> categories, ParseException error) {
            if(categories !=null)
            {
                //add all the categories into the list
                mCategoryAdapter.addAll(categories);
                //add the custom exercises footer after we have added the rest
                mListView.addFooterView(customExercisesView);
                //sort the list alphabetically
                mCategoryAdapter.sort(new Comparator<Category>() {
                    @Override
                    public int compare(Category category, Category t1) {
                        return category.getName().compareTo(t1.getName());
                    }
                });
            }
        }
    });
}


 @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //to make phone vibrate for 20 milliseconds when clicking an item in the list
    Vibrator v = (Vibrator) this.getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
    v.vibrate(20);
    //users are selecting one of the 6 main exercise categories
    if(position<=5) {
        if(mCategoryAdapter.getItem(position)!=null) {
            //giving the listed exercises in the list view the ability to be clicked on
            Category category = mCategoryAdapter.getItem(position);
            //Get category ID and name to pass to Exercise List
            mCategoryID = category.getObjectId();
            mCategoryName = category.getName();
            Intent exercise_intent = new Intent(this, ExerciseList.class);
            exercise_intent.putExtra("categoryID", mCategoryID);
            exercise_intent.putExtra("categoryName", mCategoryName);
            startActivity(exercise_intent);
        }
        else
            Toast.makeText(this, "Categories are still loading, please try again", Toast.LENGTH_SHORT).show();
    }else
    {

                    //user is selecting custom exercises
                    Intent custom_exercise_intent = new Intent(this, CustomExerciseList.class);
                    startActivity(custom_exercise_intent);


    }

Exception java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0 java.util.ArrayList.throwIndexOutOfBoundsException (ArrayList.java:255) java.util.ArrayList.get (ArrayList.java:308) android.widget.ArrayAdapter.getItem (ArrayAdapter.java:337) adam.exercisedictionary.CategoryList.onItemClick (CategoryList.java:139) android.widget.AdapterView.performItemClick (AdapterView.java:308) android.widget.AbsListView.performItemClick (AbsListView.java:1154) android.widget.AbsListView$PerformClick.run (AbsListView.java:3074) android.widget.AbsListView$3.run (AbsListView.java:3905) android.os.Handler.handleCallback (Handler.java:739) android.os.Handler.dispatchMessage (Handler.java:95) android.os.Looper.loop (Looper.java:135) android.app.ActivityThread.main (ActivityThread.java:5595) java.lang.reflect.Method.invoke (Method.java) java.lang.reflect.Method.invoke (Method.java:372) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:960) com.android.internal.os.ZygoteInit.main (ZygoteInit.java:755)


Solution

  • Thanks very much guys,

    I figured it out. I was certain the listview was filled at the time a user clicked and initiated the onclick method.

    I realized my query was retrieving from local datastore, where I have loaded the categories when starting the app while a splash screen shows. The issue was if those categories did not load at start up then this query would have nothing to retrieve from the local data store.

    The solution was to handle if the local datastore query was null by re-attempting to retrieve the values from the internet and it has solved the problem, no crashes since.

    Once a user has connected to the net and downloaded the categories they don't have to connect again because they are pinned permanently on the device.

        public void getCategoryList()
    {
        //parse query to pull all the current available exercises from the db
        ParseQuery<Category> query = ParseQuery.getQuery(Category.class).fromLocalDatastore();
        //call to parse.com to start the query
        query.findInBackground(new FindCallback<Category>() {
            @Override
            public void done(List<Category> categories, ParseException error) {
                if(categories !=null)
                {
                    mCategoryAdapter.clear();
                    //add all the categories into the list
                    mCategoryAdapter.addAll(categories);
                }
                else
                {
                    //check we have internet
                    if(DetectConnection.isConnected(getApplicationContext())) {
                        //backup get categories from net
                        getCategoryListFromParse();
                    }
                    else
                    {
                        //no internet and issues getting categories, let user know
                        Toast.makeText(getApplicationContext(),"Please check your internet connection", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }
    
     public void getCategoryListFromParse()
    {
        //parse query to pull all the current available exercises from the db
        ParseQuery<Category> query = ParseQuery.getQuery(Category.class);
        //call to parse.com to start the query
        query.findInBackground(new FindCallback<Category>() {
            @Override
            public void done(List<Category> categories, ParseException error) {
                if(categories !=null)
                {
                    Category.pinAllInBackground(categories);
                    //add all the categories into the list
                    mCategoryAdapter.addAll(categories);
                }
            }
        });
    }