Tab+ViewPager not updating instead shows weird warning expected state 3 found 2

别来无恙 提交于 2019-11-28 20:53:59

The FragmentPagerAdapter calls setUserVisibleHint(true|false) on neighbourhoods of the active fragment which changes the state of this fragments. This is at least the answer of the "weird warning messages" but it may not solve your problem.

Regarding your comment about how to solve that warning message I have created my own FragmentPagerAdapter as follows:

public abstract class AbstractTabPagerAdapter extends PagerAdapter {

    private static final String TAG = AbstractTabPagerAdapter.class.getCanonicalName();

    private final FragmentManager mFragmentManager;

    private FragmentTransaction mCurTransaction;

    private Fragment mCurrentPrimaryItem = null;

    public AbstractTabPagerAdapter(FragmentManager fragmentManager) {
        mFragmentManager = fragmentManager;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (mCurTransaction == null) {
            throw new IllegalArgumentException("current transaction must not be null");
        }
        String fragmentTag = makeFragmentName(container.getId(), position);
        Fragment fragment = (Fragment) mFragmentManager.findFragmentByTag(fragmentTag);
        if (fragment != null) {
            mCurTransaction.attach(fragment);
            Log.d(TAG, "Attaching existing fragment " + fragment + " at position " + position);
            //mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), position));
        } else {
            fragment = getItem(position);
            mCurTransaction.add(container.getId(), fragment, fragmentTag);
            Log.d(TAG, "Attaching new fragment " + fragment + " at position " + position);
        }

        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            //fragment.setUserVisibleHint(false);
        }

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (mCurTransaction == null) {
            throw new IllegalArgumentException("current transaction must not be null");
        }
        mCurTransaction.detach((Fragment) object);
        //mCurTransaction.remove((Fragment)object);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        //super.setPrimaryItem(container, position, object);
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            Log.d(TAG, "set Primary item " + position + " to " + fragment);
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
                // this command unexpectedly changes the state of the fragment which leads to a warning message and possible some strange behaviour
                //mCurrentPrimaryItem.setUserVisibleHint(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
                //fragment.setUserVisibleHint(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object fragment) {
        return ((Fragment) fragment).getView() == view;
    }

    public abstract Fragment getItem(int position);

    @Override
    public void startUpdate(ViewGroup container) {
        super.startUpdate(container);
        if (mCurTransaction != null) {
            throw new IllegalArgumentException("current transaction must not be null");
        }
        mCurTransaction = mFragmentManager.beginTransaction();
        Log.d(TAG, "FragmentTransaction started");
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commit();
            mCurTransaction = null;
            //mFragmentManager.executePendingTransactions();
            Log.d(TAG, "FragmentTransaction committed");
        } else {
            throw new IllegalArgumentException("current transaction must not be null");
        }
    }

    private String makeFragmentName(int viewId, int position) {
        if (viewId <= 0)
            throw new IllegalArgumentException("viewId " + viewId);
        return "tabpageradptr:" + getPageTitle(position) + ":" + viewId + ":" + position;
    }

}

The warning message is gone now and currently I do not experience any flaws - but I am still in the middle of research.

I spent a lot of time for this issue. Problem is you try to update viewpager in OnPageChangeListener listener, it will throw warning

not update in line

Solution:

All data change and update view should call out of OnPageChangeListener, ex: onCreateView of Fragment

My warning was gone! And viewpager update completelly

Its late but i figured a best way out using FragmentPagerAdapter , though its not eliminating the warnings, but its solving the purpose, if anyone can inform me what does that warning actually means and whats actually causing the warning, it would be of my best interest.

First in all of the fragments used in the viewpager create method as below.

public void updateView() {
  //Update whatever views or data you want to update
}

Also override method setUserVisibleHint which is used in FragmentPagerAdapter to notify if the fragment is visible to user or not.

 @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        this.isVisibleToUser = isVisibleToUser;
        super.setUserVisibleHint(isVisibleToUser);
    }

finally in your fragment add the following code to update the view/date when the fragment is visible.

@Override
    public void onStart() {
            if (isVisibleToUser)
                updateView();
    }

Then implement this in your TabFragment or Activity

viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {

                switch (position) {
                    case 0: {
                         ((Fragment) mFragmentList.get(0)).updateView();
                        break;
                    }
                    case 1: {
                         ((Fragment) mFragmentList.get(1)).updateView();
                        break;
                    }
                }
            }

This will take care of update the data consistantly, either you swipe or you click the tab, if anyone finds any issues or bugs, please comment and let me know or feel free to edit the solution

And I have voted for the solution above which gave me approach to apply this solution. Thanks @mikes

Bipin Bharti

It is not a important. It is only a warning. Please try to change the background of ViewPager layout to null(not set the background).

In view pager adjacent tabs are loaded simultaneously. So your actions in tab 1 will not be reflected in tab 2 since its already loaded. You should be using Broadcast receivers to solve this issue. Broadcast a event in tab 1 and receive the event in tab 2

The "W/FragmentManager: moveToState: … expected state 3 found 2" warning can be ignored and was removed in Support Library v24.0.0.

Quote from the official developer answer:

You don't need to do anything additional; this is an informational log message only. […]

The log itself as described here does not affect behavior. Please open a new bug if you are having other issues; conflating different issues in the same bug makes those separate issues more difficult to track.

Closing comments as the log issue has been resolved for a future release.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!