Update data in ListFragment as part of ViewPager

后端 未结 10 1851
一整个雨季
一整个雨季 2020-11-22 07:55

I\'m using the v4 compatibility ViewPager in Android. My FragmentActivity has a bunch of data which is to be displayed in different ways on different pages in my ViewPager.

相关标签:
10条回答
  • 2020-11-22 08:21

    Try to record the tag each time a Fragement is instantiated.

    public class MPagerAdapter extends FragmentPagerAdapter {
        private Map<Integer, String> mFragmentTags;
        private FragmentManager mFragmentManager;
    
        public MPagerAdapter(FragmentManager fm) {
            super(fm);
            mFragmentManager = fm;
            mFragmentTags = new HashMap<Integer, String>();
        }
    
        @Override
        public int getCount() {
            return 10;
        }
    
        @Override
        public Fragment getItem(int position) {
            return Fragment.instantiate(mContext, AFragment.class.getName(), null);
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Object obj = super.instantiateItem(container, position);
            if (obj instanceof Fragment) {
                // record the fragment tag here.
                Fragment f = (Fragment) obj;
                String tag = f.getTag();
                mFragmentTags.put(position, tag);
            }
            return obj;
        }
    
        public Fragment getFragment(int position) {
            String tag = mFragmentTags.get(position);
            if (tag == null)
                return null;
            return mFragmentManager.findFragmentByTag(tag);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 08:21

    You can copy FragmentPagerAdapter and modify some source code, add getTag() method

    for example

    public abstract class AppFragmentPagerAdapter extends PagerAdapter {
    private static final String TAG = "FragmentPagerAdapter";
    private static final boolean DEBUG = false;
    
    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;
    private Fragment mCurrentPrimaryItem = null;
    
    public AppFragmentPagerAdapter(FragmentManager fm) {
        mFragmentManager = fm;
    }
    
    
    public abstract Fragment getItem(int position);
    
    @Override
    public void startUpdate(ViewGroup container) {
    }
    
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
    
        final long itemId = getItemId(position);
    
    
        String name = getTag(position);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
    
            mCurTransaction.add(container.getId(), fragment,
                    getTag(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) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
                + " v=" + ((Fragment) object).getView());
        mCurTransaction.detach((Fragment) object);
    }
    
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
                mCurrentPrimaryItem.setUserVisibleHint(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
                fragment.setUserVisibleHint(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }
    
    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }
    
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment) object).getView() == view;
    }
    
    @Override
    public Parcelable saveState() {
        return null;
    }
    
    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
    }
    
    
    public long getItemId(int position) {
        return position;
    }
    
    private static String makeFragmentName(int viewId, long id) {
        return "android:switcher:" + viewId + ":" + id;
    }
    
    protected abstract String getTag(int position);
    }
    

    then extend it, override these abstract method,don't need to be afraid of Android Group change

    FragmentPageAdapter source code in the future

     class TimeLinePagerAdapter extends AppFragmentPagerAdapter {
    
    
        List<Fragment> list = new ArrayList<Fragment>();
    
    
        public TimeLinePagerAdapter(FragmentManager fm) {
            super(fm);
            list.add(new FriendsTimeLineFragment());
            list.add(new MentionsTimeLineFragment());
            list.add(new CommentsTimeLineFragment());
        }
    
    
        public Fragment getItem(int position) {
            return list.get(position);
        }
    
        @Override
        protected String getTag(int position) {
            List<String> tagList = new ArrayList<String>();
            tagList.add(FriendsTimeLineFragment.class.getName());
            tagList.add(MentionsTimeLineFragment.class.getName());
            tagList.add(CommentsTimeLineFragment.class.getName());
            return tagList.get(position);
        }
    
    
        @Override
        public int getCount() {
            return list.size();
        }
    
    
    }
    
    0 讨论(0)
  • 2020-11-22 08:23

    Okay, after testing the method by @barkside above, I could not get it to work with my application. Then I remembered that the IOSched2012 app uses a viewpager as well, and that is where I found my solution. It does not use any fragment ID's or Tags as these are not stored by viewpager in an easily accessible way.

    Here's the important parts from the IOSched apps HomeActivity. Pay particular attention to the comment, as therein lies the key.:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    
        // Since the pager fragments don't have known tags or IDs, the only way to persist the
        // reference is to use putFragment/getFragment. Remember, we're not persisting the exact
        // Fragment instance. This mechanism simply gives us a way to persist access to the
        // 'current' fragment instance for the given fragment (which changes across orientation
        // changes).
        //
        // The outcome of all this is that the "Refresh" menu button refreshes the stream across
        // orientation changes.
        if (mSocialStreamFragment != null) {
            getSupportFragmentManager().putFragment(outState, "stream_fragment",
                    mSocialStreamFragment);
        }
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if (mSocialStreamFragment == null) {
            mSocialStreamFragment = (SocialStreamFragment) getSupportFragmentManager()
                    .getFragment(savedInstanceState, "stream_fragment");
        }
    }
    

    And store instances of you Fragments in the FragmentPagerAdapter like so:

        private class HomePagerAdapter extends FragmentPagerAdapter {
        public HomePagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return (mMyScheduleFragment = new MyScheduleFragment());
    
                case 1:
                    return (mExploreFragment = new ExploreFragment());
    
                case 2:
                    return (mSocialStreamFragment = new SocialStreamFragment());
            }
            return null;
        }
    

    Also, remember to guard your Fragment calls like so:

        if (mSocialStreamFragment != null) {
            mSocialStreamFragment.refresh();
        }
    
    0 讨论(0)
  • 2020-11-22 08:26

    Alternatively you can override setPrimaryItem method from FragmentPagerAdapter like so:

    public void setPrimaryItem(ViewGroup container, int position, Object object) { 
        if (mCurrentFragment != object) {
            mCurrentFragment = (Fragment) object; //Keep reference to object
            ((MyInterface)mCurrentFragment).viewDidAppear();//Or call a method on the fragment
        }
    
        super.setPrimaryItem(container, position, object);
    }
    
    public Fragment getCurrentFragment(){
        return mCurrentFragment;
    }
    
    0 讨论(0)
  • 2020-11-22 08:27

    OK, I think I've found a way to perform request b) in my own question so I'll share for others' benefit. The tag of fragments inside a ViewPager is in the form "android:switcher:VIEWPAGER_ID:INDEX", where VIEWPAGER_ID is the R.id.viewpager in XML layout, and INDEX is the position in the viewpager. So if the position is known (eg 0), I can perform in updateFragments():

          HomeListFragment fragment = 
              (HomeListFragment) getSupportFragmentManager().findFragmentByTag(
                           "android:switcher:"+R.id.viewpager+":0");
          if(fragment != null)  // could be null if not instantiated yet
          {
             if(fragment.getView() != null) 
             {
                // no need to call if fragment's onDestroyView() 
                //has since been called.
                fragment.updateDisplay(); // do what updates are required
             }
          }
    

    I've no idea if this is a valid way of doing it, but it'll do until something better is suggested.

    0 讨论(0)
  • 2020-11-22 08:29

    This is my solution since I don't need to keep track of my tabs and need to refresh them all anyway.

        Bundle b = new Bundle();
        b.putInt(Constants.SharedPreferenceKeys.NUM_QUERY_DAYS,numQueryDays);
        for(android.support.v4.app.Fragment f:getSupportFragmentManager().getFragments()){
            if(f instanceof HomeTermFragment){
                ((HomeTermFragment) f).restartLoader(b);
            }
        }
    
    0 讨论(0)
提交回复
热议问题