java.lang.IllegalStateException: Fragement no longer exists for key f0: index 0
2016-10-26 10:53
369 查看
先来看下异常信息
java.lang.IllegalStateException: Fragement no longer exists for key f0: index 0
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:564)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:427)
加载完数据后,调用setAdapter出错,根本原因是getFragment中出现的异常,接下来看下异常堆栈的源码,以下是ViewPager.setAdapter源码。
1. ViewPager.setAdapter
[java]
view plain
copy
print?
/**
* Set a PagerAdapter that will supply views for this pager as needed.
*
* @param adapter Adapter to use
*/
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
}
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new PagerObserver();
}
mAdapter.registerDataSetObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
mExpectedAdapterCount = mAdapter.getCount();
if (mRestoredCurItem >= 0) {
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
populate();
} else {
requestLayout();
}
}
if (mAdapterChangeListener != null && oldAdapter != adapter) {
mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
}
}
2. FragmentStatePagerAdapter.restoreState(Parcelable state, ClassLoader loader) {
Fragment f = mFragmentManager.getFragment(bundle, key);
3. android.support.v4.app.FragmentManager.getFragment
[java]
view plain
copy
print?
@Override
public Fragment getFragment(Bundle bundle, String key) {
int index = bundle.getInt(key, -1);
if (index == -1) {
return null;
}
if (index >= mActive.size()) {
throwException(new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index));
}
Fragment f = mActive.get(index);
if (f == null) {
throwException(new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index));
}
return f;
}
从bundle中可以取出来,但是有两种情况会抛出此异常,吐槽下为啥两种情况抛出的日志一模一样。
1.没有存活的Fragment
2.获取到的Fragemnt为空
* 问题是Bundle从哪里来的?
从以上ViewPager.setAdapter代码中可以看出传递的bundle是ViewPager.mRestoredAdapterState,在ViewPager的上下文进行查找此变量,可获知仅以下一个函数onRestoreInstanceState中进行了赋值操作。
[java]
view plain
copy
print?
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
if (mAdapter != null) {
mAdapter.restoreState(ss.adapterState, ss.loader);
setCurrentItemInternal(ss.position, false, true);
} else {
mRestoredCurItem = ss.position;
mRestoredAdapterState = ss.adapterState;
mRestoredClassLoader = ss.loader;
}
}
通过函数名可以看出跟状态的存储与取出有关,详情可以查看以下文章。
《View的onSaveInstanceState和onRestoreInstanceState过程分析》
由onRestoreInstanceState源码可以看出,出问题处的bundle是从此函数的state参数中获取的。既然onRestoreInstanceState这个函数是获取存储的状态,就来看下保存状态onSaveInstanceState的代码。
[java]
view plain
copy
print?
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.position = mCurItem;
if (mAdapter != null) {
ss.adapterState = mAdapter.saveState();
}
return ss;
}
由以上可以看出只有在此ViewPager已经设置过mAdapter才会触发saveState(),接着来看下FragmentStatePagerAdapter.saveState()的源码
[java]
view plain
copy
print?
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
由此找到了Bundle的根源,网上解决此BUG的一种解法就是覆写此函数返回为空,这样FragmentManager.getFragment函数中就不满足第一个判断条件,不会执行后续代码也不会抛出异常了。
[java]
view plain
copy
print?
@Override
public Parcelable saveState() {
return null;
}
文章地址:
《java.lang.IllegalStateException: Fragement no longer exists for key f1: index 3》
java.lang.IllegalStateException: Fragement no longer exists for key f0: index 0
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:564)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:427)
加载完数据后,调用setAdapter出错,根本原因是getFragment中出现的异常,接下来看下异常堆栈的源码,以下是ViewPager.setAdapter源码。
1. ViewPager.setAdapter
[java]
view plain
copy
print?
/**
* Set a PagerAdapter that will supply views for this pager as needed.
*
* @param adapter Adapter to use
*/
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
}
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new PagerObserver();
}
mAdapter.registerDataSetObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
mExpectedAdapterCount = mAdapter.getCount();
if (mRestoredCurItem >= 0) {
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
populate();
} else {
requestLayout();
}
}
if (mAdapterChangeListener != null && oldAdapter != adapter) {
mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
}
}
2. FragmentStatePagerAdapter.restoreState(Parcelable state, ClassLoader loader) {
Fragment f = mFragmentManager.getFragment(bundle, key);
3. android.support.v4.app.FragmentManager.getFragment
[java]
view plain
copy
print?
@Override
public Fragment getFragment(Bundle bundle, String key) {
int index = bundle.getInt(key, -1);
if (index == -1) {
return null;
}
if (index >= mActive.size()) {
throwException(new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index));
}
Fragment f = mActive.get(index);
if (f == null) {
throwException(new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index));
}
return f;
}
从bundle中可以取出来,但是有两种情况会抛出此异常,吐槽下为啥两种情况抛出的日志一模一样。
1.没有存活的Fragment
2.获取到的Fragemnt为空
* 问题是Bundle从哪里来的?
从以上ViewPager.setAdapter代码中可以看出传递的bundle是ViewPager.mRestoredAdapterState,在ViewPager的上下文进行查找此变量,可获知仅以下一个函数onRestoreInstanceState中进行了赋值操作。
[java]
view plain
copy
print?
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
if (mAdapter != null) {
mAdapter.restoreState(ss.adapterState, ss.loader);
setCurrentItemInternal(ss.position, false, true);
} else {
mRestoredCurItem = ss.position;
mRestoredAdapterState = ss.adapterState;
mRestoredClassLoader = ss.loader;
}
}
通过函数名可以看出跟状态的存储与取出有关,详情可以查看以下文章。
《View的onSaveInstanceState和onRestoreInstanceState过程分析》
由onRestoreInstanceState源码可以看出,出问题处的bundle是从此函数的state参数中获取的。既然onRestoreInstanceState这个函数是获取存储的状态,就来看下保存状态onSaveInstanceState的代码。
[java]
view plain
copy
print?
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.position = mCurItem;
if (mAdapter != null) {
ss.adapterState = mAdapter.saveState();
}
return ss;
}
由以上可以看出只有在此ViewPager已经设置过mAdapter才会触发saveState(),接着来看下FragmentStatePagerAdapter.saveState()的源码
[java]
view plain
copy
print?
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
由此找到了Bundle的根源,网上解决此BUG的一种解法就是覆写此函数返回为空,这样FragmentManager.getFragment函数中就不满足第一个判断条件,不会执行后续代码也不会抛出异常了。
[java]
view plain
copy
print?
@Override
public Parcelable saveState() {
return null;
}
文章地址:
《java.lang.IllegalStateException: Fragement no longer exists for key f1: index 3》
相关文章推荐
- java.lang.IllegalStateException: Fragement no longer exists for key f0: index 0
- java.lang.IllegalStateException: Fragement no longer exists for key f0: index 0
- Fragment no longer exists for key f0: index 0
- Fragment no longer exists for key f0: index 0
- java.lang.IllegalStateException: No value for key [org.hibernate.impl.SessionFactoryImpl@af9ce7] bou
- type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds int,java.lang.Object
- java.lang.IllegalStateException: ImageView no longer exists. You should not use this PhotoViewAttacher any more.
- java.lang.SecurityException: No active admin owned by uid 10065 for policy&&锁屏功能的实现
- Mybatis-There is no getter for property named 'id' in 'class java.lang.String'
- There is no getter for property named '**' in 'class java.lang.String
- mybatis There is no getter for property named 'xx' in 'class java.lang.String 没有写 xinwen.setsavetype
- Storm DRPC ERROR: java.lang.RuntimeException: No DRPC servers configured for topology
- javax.validation.UnexpectedTypeException: No validator could be found for type: java.lang.Integer
- GAE for Java exception: no matching index found.
- GAE for Java exception: no matching index found.
- There is no getter for property named 'num' in 'class java.lang.String'。
- There is no getter for property named '**' in 'class java.lang.String'
- Spring+dwr在保存数据时报错ERROR [DefaultConverterManager][convertOutbound] No converter found for 'java.lang
- No mapping found for dependency [type=java.lang.String, name='struts.objectFactory.spring.autoWire.
- java.lang.IllegalStateException: No data type for node: org.hibernate.hql.ast.tree.MethodNode(尼玛,蛋疼的错误)