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)
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);
}
}
});
}