FragmentStatePagerAdapter with ChildFragmentManage

2019-01-13 21:27发布

EDIT 2

I now managed to get rid of the error with using the trick from here https://code.google.com/p/android/issues/detail?id=42601#c10 so that's the reoson why my last edit is placed on top of my question.

But this led to the next error:

java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281)
at android.view.View.dispatchRestoreInstanceState(View.java:12043)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android.view.View.restoreHierarchyState(View.java:12021)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:425)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4800)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)

And now I don't know where to continue...

Edit 0 - FIRST question

I get following exception:

java.lang.IllegalStateException: No activity
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1091)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1492)
at android.support.v4.app._HoloFragment.performActivityCreated(_HoloFragment.java:251)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4800)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)

I have no idea where to start. I'm using the up to date support library (v4, rev18).

Everything works fine until I add a Fragment which holds a ViewPager in combination with FragmentStatePagerAdapter.

I'm using the support library everywhere, I tried the solutions from https://code.google.com/p/android/issues/detail?id=42601...

But nothing worked yet...

I don't know where to start, does anyone have a hint?

EDIT 1: BACKGROUND and Code

1) In my MainActivity I use following:

The third page has the viewpager...

public void setPage(int pos, boolean addToBackStack)
 {
    Fragment nextFragment = null;
    FragmentTransaction transaction = null;

    switch (pos)
    {
        case 0:
            if (mFragmentAllRoutines == null)
                mFragmentAllRoutines = new RoutinesListFragment();
            if (!mFragmentAllRoutines.isVisible())
                nextFragment = mFragmentAllRoutines;
            break;
        case 1:
            if (mFragmentRoutine == null)
                mFragmentRoutine = new RoutineFragment();
            if (!mFragmentRoutine.isVisible())
                nextFragment = mFragmentRoutine;
            break;
        case 2:
            if (mFragmentDay == null)
                mFragmentDay = new RoutineDayFragment();
            if (!mFragmentDay.isVisible())
                nextFragment = mFragmentDay;
            break;
        default:
            break;
    }

    if (nextFragment != null)
    {
        // Fragment prevFragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
        transaction = getSupportFragmentManager().beginTransaction();
        // if (prevFragment != null)
        //    transaction.detach(prevFragment);
        transaction.replace(R.id.fragment, nextFragment, nextFragment.getClass().getName());
        // transaction.attach(nextFragment);
        if (addToBackStack)
            transaction.addToBackStack(null);
        transaction.commit();
    }
}

2) the third fragment:

It's a simple Fragment with a ViewPager and a FragmentStatePagerAdapter. The FragmentStatePagerAdapter get's the getChildFragmentManager() as FragmentManager. And somewhere there seems to be the problem.

4条回答
戒情不戒烟
2楼-- · 2019-01-13 21:34

I would need to see more code in order to know where to apply this ... but I had a similar situation as you did... I solved the ChildFragmentManager issue the same way, and got the same NullPointerException, as you have.

I did manage to solve it... I'll try to describe my solution, as with the code you supplied I am unsure as to where to apply the "fix" ... It really is a fix ... it's not an elegant way to solve this! It did however helped me, and I don't need to restore states once I navigate away on the view Pager, so no downside for me.

I have multiple Fragments, that implement the static bit of code and the onDetach (on https://code.google.com/p/android/issues/detail?id=42601#c10), each fragment has a pager, and onCreateView I attach an adapter that extends FragmentStatePagerAdapter.

on those adapters I have overridden the restoreState method to do nothing

    @Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
    //do nothing here! no call to super.restoreState(arg0, arg1);
}

Again, this is not the best way... but it did solve my problem.

Best of luck!

查看更多
Deceive 欺骗
3楼-- · 2019-01-13 21:39

I have just stumbled upon the same problem.

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
     at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:873)
     at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:215)

The solution by Marc works but in my case it caused lags on the Fragment with FragmentStatePagerAdapter. So I overrode restoreState, called super, wrapped it in try/catch and it worked with no lags.

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    try{
        super.restoreState(state, loader);
    }catch (NullPointerException e){
        // null caught
    }
}

UPDATE:

I Have been using this solution in production since then. So it is safe to use.

查看更多
我只想做你的唯一
4楼-- · 2019-01-13 21:53

On my side, I was keeping a reference to the ViewPager fragments in a containing fragment and was using onSaveInstanceState to store their states. I think the NPE occurred because this was colliding with the ViewPager own mechanism to restore the fragments. What I did, change my architecture from a ViewPager to fragment transactions I manage myself. (ViewPager was not an appropriate solution for my case)

查看更多
Evening l夕情丶
5楼-- · 2019-01-13 21:53

First of all, English is not my mother tongue, if I have something wrong in grammar,please tell me. I encountered this problem in my project. At first I did what Marc said, and it worked well. But when I added another ViewPager in a father fragment, the new ViewPager showed as same as the old one no matter what kinda code in this new viewpager. At last I found the reason. We always create Fragment by using FragmentTrasaction.replace(R.layout.fragment,fragment) method. Because of this, we create a new fragment instance when we use this method. Instead of using replace() method, I use FragmentTransaction.hide() and show() method to switch fragment. I solved my problem this way. Here is my code snippets :

@Override
public void onClick(View v) {
    FragmentTransaction transaction = fm.beginTransaction();
    switch (v.getId()) {
        case R.id.tv_schedule_day:
        hideFragment(transaction);
        if (dayFragment == null) {
            dayFragment = new ScheduleDayFragment();
            transaction.add(R.id.ll_schedule_content, dayFragment);
        } else {
            transaction.show(dayFragment);
        }
        transaction.commit();
        break;
        case R.id.tv_schedule_week:
        hideFragment(transaction);
        if (weekFragment == null) {
            weekFragment = new ScheduleWeekFragment();
            transaction.add(R.id.ll_schedule_content, weekFragment);
        } else {
            transaction.show(weekFragment);
        }
        transaction.commit();
        break;
    case R.id.tv_schedule_month:
        hideFragment(transaction);
        if (monthFragment == null) {
            monthFragment = new ScheduleMonthFragment();
            transaction.add(R.id.ll_schedule_content, monthFragment);
        } else {
            transaction.show(monthFragment);
        }
        transaction.commit();
        break;

private void hideFragment(FragmentTransaction transaction) {
    if (dayFragment != null) {
        transaction.hide(dayFragment);
    }
    if (weekFragment != null) {
        transaction.hide(weekFragment);
    }
    if (monthFragment != null) {
        transaction.hide(monthFragment);
    }
}

I use hide() and show() methods to make switch father fragment, so when I use getChildFragmentManager() in embedded fragment, it wolud not return null. This question was asked in 2013, I think no one would see this answer, but I am still very glad to anwser this question.

查看更多
登录 后发表回答