8

I have a mainactivity which includes a TabLayout with ViewPager

I have added 3 tabs and each tab has separate fragments which contains a recyclerview, and these recyclerviews has a checkbox that should be simultaneously updated/refreshed whenever i swipe the viewpager(i save checked positions in shared preference and updates via shared preference).

My problem here is whenever i check a checkbox in tab1, tab2 is not updating/refreshing until i scroll down the Recyclerview. and tab3 is working fine. and i am getting a weird warning in logcat too.

 03-05 09:35:53.345 4317-4327/com.example.rubin W/art: Suspending all threads took: 6.805ms
    03-05 09:35:58.310 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab3{10a5f1f0 #2 id=0x7f0d00b6} not updated inline; expected state 3 found 2
    03-05 09:36:01.363 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab1{2d9aa887 #1 id=0x7f0d00b6} not updated inline; expected state 3 found 2 

My PagerAdapter

public class PagerAdapter1 extends FragmentStatePagerAdapter {
    int mNumOfTabs;
    public PagerAdapter1(FragmentManager fm, int NumOfTabs) {
        super(fm);
        this.mNumOfTabs = NumOfTabs;
    }
    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
               return new Tab1();
            case 1:
               return new Tab2();
            case 2:
               return new Tab3();

            default:
                return null;

        }
    }

    @Override
    public int getCount() {
        return mNumOfTabs;
    }
}

Tablayout OnPageChangelistener

final PagerAdapter1 adapter = new PagerAdapter1
                (getSupportFragmentManager(), tabLayout1.getTabCount(), getApplicationContext());
        viewPager1.setAdapter(adapter);
        viewPager1.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout1));
        tabLayout1.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager1.setCurrentItem(tab.getPosition());
                adapter.notifyDataSetChanged();
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });
    }

code for each fragments.

 public class Tab1 extends Fragment {

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.home_tab1_recycler, container, false);
            RecyclerView rv = (RecyclerView) v.findViewById(R.id.home_recyclerview);   
            LinearLayoutManager llm = new LinearLayoutManager(getContext());
            rv.setLayoutManager(llm);
            rv.setHasFixedSize(true); // to improve performance
            rv.setAdapter(new HomeManager()); // the projectdatabase manager is assigner to the RV
            return v;
        }

        public class HomeManager extends RecyclerView.Adapter<HomeManager.RecyclerViewHolder> {
    int Length,h;
 View v1;
        ArrayList<String> PROJECT_ID = new ArrayList<String>();
Set<String> set;
        List<String> selected;
     public class RecyclerViewHolder extends RecyclerView.ViewHolder {
     CheckBox mCheck;
      RecyclerViewHolder(final View itemView) {
                    super(itemView);
      mCheck = (CheckBox) itemView.findViewById(R.id.PROJECT_fav);
     SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
                    set = pref.getStringSet("FAV", null);
      if (set != null) {
                        selected = new ArrayList<String>(set);
                    } else {
                        selected = new ArrayList<String>();
                    }
    mCheck.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
     h = getAdapterPosition();
    check = PROJECT_ID.get(h); // for saving the project id from json.
     if (selected.contains(check)) {
                                    selected.remove(check);
                                    mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
                                    Snackbar snackbar = Snackbar.make(v, "Property Unfavorited", Snackbar.LENGTH_SHORT);
                                    snackbar.show();
                                } else {
                                    selected.add(check);
                                    mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
                                    Snackbar snackbar = Snackbar.make(v, "Property Favorited", Snackbar.LENGTH_SHORT);
                                    snackbar.show();

                                }
                                Log.e("HF update checked", String.valueOf(selected));
                                Set<String> set = new HashSet<String>();
                                set.addAll(selected);
                                SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
                                SharedPreferences.Editor editor = pref.edit();
                                editor.putStringSet("FAV", set);
                                editor.commit();
                            }
         }
                    });
     @Override
            public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
                v1 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item, viewGroup, false);
                return new RecyclerViewHolder(v1);
            }

            @Override
            public void onBindViewHolder(final RecyclerViewHolder viewHolder, int i) {
    SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
                set = pref.getStringSet("FAV", null);
                if (set != null) {
                    selected = new ArrayList<String>(set);
                } else {
                    selected = new ArrayList<String>();
                }
                Log.e("HF update UI", String.valueOf(selected));
    if (String.valueOf(selected).contains(String.valueOf(PROJECT_ID.get(i)))) {
                        viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
                    } else {
                        viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
                    }
                }
     @Override
            public int getItemCount() {
                //Code for Total length of json
                return Length;
            }
Mr Robot
  • 1,747
  • 6
  • 35
  • 67
  • 1
    So checking something in tab1 is supposed to update tab 2? – Joe Maher Mar 05 '16 at 04:46
  • yes . it should be updated in tab 2 and tab 3, but tab2 is updating only when scroll down therecyclerview and tab 3 is working fine. – Mr Robot Mar 05 '16 at 04:47
  • 2
    Well likely whats happening is that going to tab 2 is calling something (maybe `adapter.notifyDataSetChanged();`) that is updating tab 3. – Joe Maher Mar 05 '16 at 04:49
  • 2
    Try placing `adapter.notifyDataSetChanged();` in onTabUnselected – Joe Maher Mar 05 '16 at 04:49
  • No. still tab2 is not updating the change. but tab3 does . – Mr Robot Mar 05 '16 at 04:51
  • but if i check a checkbox in tab 2 , tab1 and tab3 is updating ,but it also happening after more than one swipe . – Mr Robot Mar 05 '16 at 04:53
  • 1
    Going to need to see more code then beause something to do with the tab changing is triggering updates, but only after arriving in a tab (ie. the current tab doesn't know it needs to update as well) – Joe Maher Mar 05 '16 at 04:53
  • @JoeMaher: when i searched about that error, i got this https://code.google.com/p/android/issues/detail?id=202037&q=nexus%204&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars from google . Is that related to my problem.? – Mr Robot Mar 05 '16 at 04:58
  • 1
    The thing with viewpagers is that they load the next pages as well. You could override by changing setPageLimit on the viewpager, but the minimum is one. I think loading simultaneous pages with the view pager may be your issue. – Taylor Courtney Mar 05 '16 at 06:09
  • @TaylorCourtney: i tried `viewPager1.setOffscreenPageLimit(0);` . but still the same result – Mr Robot Mar 05 '16 at 06:15
  • 1
    It can't be zero. It probably used 1. – Taylor Courtney Mar 05 '16 at 06:16
  • 1
    I don't see where you are setting the check box position from preferences. Please post that. – Taylor Courtney Mar 05 '16 at 06:17
  • @TaylorCourtney:added the code of fragment. – Mr Robot Mar 05 '16 at 06:34
  • 1
    Try using different variable names for each string in the shared preferences in the fragments. – Taylor Courtney Mar 05 '16 at 15:21
  • @JoeMaher `@Override public void setMenuVisibility(final boolean visible) { super.setMenuVisibility(visible); if (visible) { Log.e("fragment Visible","true"); }else{ Log.e("fragment Visible","false"); } }` i just added this code to my tab2 fragment. and then i called `viewPager1.getAdapter().notifyDataSetChanged();` in onTabUnselected as you told. Now everything works correctly, but viewpager is very very slow on swipe.. – Mr Robot Mar 07 '16 at 03:48
  • 3
    Did you recently update to the support library version 23.2.0? I just did and I got a very similar problem. I've since downgraded to 23.1.1, and I no longer get the issue. May be an issue with the update. – Adam Nelson Mar 09 '16 at 07:38
  • 2
    There's an issue in 23.2.0, you can keep an eye here https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened&groupby=&sort=&id=202037 – DDsix Mar 27 '16 at 08:58

6 Answers6

4

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.

mikes
  • 2,323
  • 1
  • 16
  • 11
2

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).

Iulia Barbu
  • 1,522
  • 12
  • 25
Bipin Bharti
  • 1,034
  • 2
  • 14
  • 27
2

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

cuasodayleo
  • 466
  • 5
  • 16
  • 1
    i didnt understood it completely, can you pls show me an example ..?? – Mr Robot May 04 '16 at 05:29
  • @Ruben in onTabSelected, just call 'viewPager1.setCurrentItem(tab.getPosition());' only, notifydatasetChange is in this method is incorrect, it will throw warning and fragment not update inline – cuasodayleo May 07 '16 at 02:10
  • I do not care about warning, but the middle tab is not updating properly. it still shows the old result. – Mr Robot Jul 09 '16 at 05:49
2

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

PravinDodia
  • 3,271
  • 1
  • 18
  • 22
2

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

Sachin Thampan
  • 893
  • 7
  • 17
1

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.

lejonl
  • 1,453
  • 15
  • 20