I have a ViewPager with three items. I am trying to set the ViewPager to view the page furthest to the right (which would be the 2nd element). This is returning an IndexOutOfBounds exception, though I know the index ought to be in bounds. Here is the exact stack:
02-22 12:22:50.256: E/AndroidRuntime(384): FATAL EXCEPTION: main
02-22 12:22:50.256: E/AndroidRuntime(384): java.lang.IndexOutOfBoundsException: index=1 count=0
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.addInArray(ViewGroup.java:2050)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.addViewInner(ViewGroup.java:1994)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.addViewInLayout(ViewGroup.java:1958)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.addViewInLayout(ViewGroup.java:1939)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.support.v4.view.ViewPager.addView(ViewPager.java:917)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.addView(ViewGroup.java:1828)
02-22 12:22:50.256: E/AndroidRuntime(384): at us.tagverse.pagertest.MasterActivity$PAdapter.instantiateItem(MasterActivity.java:518)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.support.v4.view.PagerAdapter.instantiateItem(PagerAdapter.java:110)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:649)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.support.v4.view.ViewPager.populate(ViewPager.java:783)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1016)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1017)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.widget.LinearLayout.measureVertical(LinearLayout.java:386)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.widget.LinearLayout.onMeasure(LinearLayout.java:309)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewRoot.performTraversals(ViewRoot.java:839)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.os.Handler.dispatchMessage(Handler.java:99)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.os.Looper.loop(Looper.java:123)
02-22 12:22:50.256: E/AndroidRuntime(384): at android.app.ActivityThread.main(ActivityThread.java:3683)
02-22 12:22:50.256: E/AndroidRuntime(384): at java.lang.reflect.Method.invokeNative(Native Method)
02-22 12:22:50.256: E/AndroidRuntime(384): at java.lang.reflect.Method.invoke(Method.java:507)
02-22 12:22:50.256: E/AndroidRuntime(384): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-22 12:22:50.256: E/AndroidRuntime(384): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-22 12:22:50.256: E/AndroidRuntime(384): at dalvik.system.NativeStart.main(Native Method)
Note that the cause is java.lang.IndexOutOfBoundsException: index=1 count=0
. This would imply that the count of the pages/items is 0 and the index I am requesting is 1. Neither of these things are true. Here is how I am calling my ViewPager and requesting the given page:
ViewPager pager = (ViewPager) findViewById(R.id.ma_viewcontainer);
PAdapter adapter = new PAdapter();
pager.setAdapter(adapter);
pager.setCurrentItem(2);
Note that this call does not give any error, and correctly sets the current item to the middle item (index 1):
ViewPager pager = (ViewPager) findViewById(R.id.ma_viewcontainer);
PAdapter adapter = new PAdapter();
pager.setAdapter(adapter);
pager.setCurrentItem(1);
I have a count of 3 items in the view pager. Here is my full PAdapter class, which extends the PagerAdapter class:
private class PAdapter extends PagerAdapter implements TitleProvider {
private int COUNT = 3;
private static final int SETTINGS_ACTIVITY = 0;
private static final int MAIN_ACTIVITY = 1;
private static final int FRIEND_LIST_ACTIVITY = 2;
@Override
public int getCount() {
return COUNT;
}
@Override
public Object instantiateItem(View collection, int position) {
LinearLayout layout = new LinearLayout(getApplicationContext());
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
switch(position) {
case MAIN_ACTIVITY :
layout = (LinearLayout) inflater.inflate(R.layout.main, null, false);
initMainLayout(layout);
break;
case SETTINGS_ACTIVITY :
layout = (LinearLayout) inflater.inflate(R.layout.settings, null, false);
initSettingsLayout(layout);
break;
case FRIEND_LIST_ACTIVITY :
layout = (LinearLayout) inflater.inflate(R.layout.friend_list, null, false);
initFriendListLayout(layout);
break;
}
((ViewPager)collection).addView(layout, position);
return layout;
}
@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager)collection).removeView((LinearLayout)view);
}
@Override
public boolean isViewFromObject(View v, Object o) {
return v == (LinearLayout)o;
}
@Override
public void finishUpdate(View arg0) {
//no need
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//no need
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void startUpdate(View arg0) {
//no need
}
@Override
public String getTitle(int position) {
Resources res = getApplicationContext().getResources();
switch(position) {
case MAIN_ACTIVITY :
return res.getString(R.string.app_name);
case SETTINGS_ACTIVITY :
return res.getString(R.string.settings);
case FRIEND_LIST_ACTIVITY :
return res.getString(R.string.friend_list);
default :
return null;
}
}
}
The line ((ViewPager)collection).addView(layout, position);
causes the crash.
As you can see, three items. Using setCurrentItem() with a parameter of 0 or 1 works just fine, but 2 causes this strange error. I've run out of ideas to solve it... unfortunately ViewPager resides in some uncharted waters of Android it seems. If anyone has some insight on how to solve this it would be much appreciated. Thanks!
EDIT: As per Shereef's suggestion, I tried logging the child count via collection.getChildCount() and got the following result:
02-22 15:20:42.274: E/children count(645): count: 0
02-22 15:20:42.454: E/children count(645): count: 1
02-22 15:20:42.594: E/children count(645): count: 2
This is interesting. What this tells me is that its creating an empty PagerAdapter and adding them one at a time. instantiateItem()
is called 3 times for the three visible views (center, left, and right). So I added this block of code inside the instantiateItem()
method:
if(((ViewPager)collection).getChildCount() == 2) {
((ViewPager)collection).setCurrentItem(2);
}
So only if the count is established to be 2 will it set the page to 2 (this is a hacky solution which doesn't fully address the problem, but was worth a try). I got a similar error stack which pointed first to the line: ((ViewPager)collection).setCurrentItem(2);
, then ((ViewPager)collection).addView(layout, position);
.
Hope this helps give some insight.
I dont think you can just do ((ViewPager)collection).addView(layout, position)
. It depends on your off screen page limit, which by default is 1, I believe. I assume you are only using 3 views, so you can do something like viewPager.setOffscreenPageLimit(3);
in your `onCreate (or wherever you placed your call) to avoid each view being refreshed every time you leave it.
You will see in a few tutorials that ((ViewPager) collection).addView(view, 0);
is used in instantiateItem()
. I have worked quite a bit with ViewPagers
in the past few weeks, and using 0 as the position -all- the time seems to work just fine.
I see the crash log I see that it crashes in instantiate item. I don"t know which line exactly because I don't have your line numbers
But if i was a betting man, I would bet that:
((ViewPager)collection).addView(layout, position);
Crashes for trying to add view at position 1 while there are no pages in the collection
Maybe check the collection.getchildcount()
(maybe the method name is wrong) and insert at max(position,count)
i.e replace position with:
count > position ? position : count
EDIT:
((ViewPager)collection).addView(layout, ((ViewPager)collection).getChildCount() > position ? position : ((ViewPager)collection).getChildCount())
p.s. Posting from my phone sorry for the horrible formatting
Please notice
02-22 12:22:50.256: E/AndroidRuntime(384): at us.tagverse.pagertest.MasterActivity$PAdapter.instantiat
MasterActivity.java:518
The number at the end of the line i copied and find out which line is it then and only then you will know which line got the crash
EDIT: P.S. about your solution
I think your solution only sets the current item after the 3 pages were instantiated by instantiate item, but my line would make it work even if they did not get instantiated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With