【问题标题】:How to force re-create fragments from FragmentStatePagerAdapter child如何强制从 FragmentStatePagerAdapter 子重新创建片段
【发布时间】:2013-05-27 17:31:09
【问题描述】:

有一个问题我似乎找不到问题。

我有一个实现自定义 TabAdapter 的 FragmentStatePagerAdapter。这里一切正常,除了我遇到的情况是 FragmentStatePagerAdapter 中的一个片段可能会更改一些需要所有片段重新创建自己的视图的项目。

例如,在 Fragment D 中,用户更改了某些内容 -> 然后 Fragment A、B、C 中的值需要更改。这会立即发生在片段 A 和 B 中,因为它们的视图尚未创建。但是,片段 C 已经创建,因为似乎始终创建了 3 个片段,至少在默认情况下(上一个、当前、下一个)。因此,片段 C 没有得到更新。

所以最终我需要一种方法来强制适配器中的所有片段在其中一个片段(A、B、C 或 D)发生变化时重新创建它们的视图。

这是我的 FragmentStatePagerAdapter

public class MyTabsAdapter extends FragmentStatePagerAdapter implements
    TabsAdapter {

private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private final ViewPager mPager;

private Activity mContext;

/*
 * TabInfo- Simple object to keep track of the tabs.
 */
private class TabInfo {
    private String fragName;
    private String title;

    TabInfo(String fragName, String title) {
        this.fragName = fragName;
        this.title = title;
    }

    String getFragName() {
        return this.fragName;
    }

    String getTitle() {
        return this.title;
    }
}

public MyTabsAdapter(FragmentActivity ctx, ViewPager pager) {
    super(ctx.getSupportFragmentManager());
    this.mContext = ctx;
    this.mPager = pager;

    this.mPager.setAdapter(this);
}

/*
 * getView - get Tab view
 */
@SuppressLint("DefaultLocale")
public View getView(int position) {
    Button tab;

    LayoutInflater inflater = mContext.getLayoutInflater();
    tab = (Button) inflater.inflate(R.layout.tab_scrolling, null);

    tab.setText(this.mTabs.get(position).getTitle().toUpperCase());

    return tab;
}

public void addTab(String fragName, String title) {
    TabInfo info = new TabInfo(fragName, title);
    mTabs.add(info);
}

@Override
public Fragment getItem(int position) {
    String fragName = mTabs.get(position).getFragName();
    if (fragName == "FragmentA") {
        return FragmentA.newInstance();
    } else if (fragName == "FragmentB") {
        return FragmentB.newInstance();
    } else if (fragName == "FragmentC") {
        return FragmentC.newInstance();
    } else if (fragName == "FragmentD") {
        return FragmentD.newInstance();
    }

    return null;
}

@Override
public int getCount() {
    return mTabs.size();
}

}

片段被简单地添加到这里:

MyTabsAdapter mAdapter = new MyTabsAdapter(this, myViewPager);
mAdapter.addTab("FragmentB", "Fragment B")

这一切都很好,我对选项卡适配器/视图/等没有任何问题。只是在寻找如何在 FragmentA/B/C/D 发生变化时“强制”适配器删除/重新创建其他项目。

谢谢,如有需要会提供更多信息

【问题讨论】:

    标签: android android-viewpager adapter fragment


    【解决方案1】:

    如果您需要更改适配器数据以删除或重新创建,我已在 android Support4Demos 中进行了简单更改,以演示我如何更新适配器的片段页面。

    /**
     * Demonstrates combining a TabHost with a ViewPager to implement a tab UI
     * that switches between tabs and also allows the user to perform horizontal
     * flicks to move between the tabs.
     */
    public class FragmentTabsPager extends FragmentActivity implements View.OnClickListener,FragmentCallBack{
    
        TabHost mTabHost;
        ViewPager  mViewPager;
    
        TabsAdapter mTabsAdapter;
    
        private Button mBtn_nextFragment;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.fragment_tabs_pager);
            mTabHost = (TabHost)findViewById(android.R.id.tabhost);
    
            mBtn_nextFragment=(Button)findViewById(R.id.btn_next_fragment);
    
            mBtn_nextFragment.setOnClickListener(this);
    
            mTabHost.setup();
    
            mViewPager = (ViewPager)findViewById(R.id.pager);
    
            mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
    
            mTabsAdapter.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                    FragmentStackSupport.CountingFragment.class, null);
            mTabsAdapter.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                    LoaderCursorSupport.CursorLoaderListFragment.class, null);
            mTabsAdapter.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                    LoaderCustomSupport.AppListFragment.class, null);
            mTabsAdapter.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                    LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    
            if (savedInstanceState != null) {
                mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
            }
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putString("tab", mTabHost.getCurrentTabTag());
        }
    
        /**
         * This is a helper class that implements the management of tabs and all
         * details of connecting a ViewPager with associated TabHost.  It relies on a
         * trick.  Normally a tab host has a simple API for supplying a View or
         * Intent that each tab will show.  This is not sufficient for switching
         * between pages.  So instead we make the content part of the tab host
         * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
         * view to show as the tab content.  It listens to changes in tabs, and takes
         * care of switch to the correct paged in the ViewPager whenever the selected
         * tab changes.
         */
        public static class TabsAdapter extends FragmentStatePagerAdapter
                implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
            private final Context mContext;
            private final TabHost mTabHost;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
    
            static final class TabInfo {
                private final String tag;
                private final Class<?> clss;
                private final Bundle args;
    
                TabInfo(String _tag, Class<?> _class, Bundle _args) {
                    tag = _tag;
                    clss = _class;
                    args = _args;
                }
            }
    
            static class DummyTabFactory implements TabHost.TabContentFactory {
                private final Context mContext;
    
                public DummyTabFactory(Context context) {
                    mContext = context;
                }
    
                @Override
                public View createTabContent(String tag) {
                    View v = new View(mContext);
                    v.setMinimumWidth(0);
                    v.setMinimumHeight(0);
                    return v;
                }
            }
    
            public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
                super(activity.getSupportFragmentManager());
                mContext = activity;
                mTabHost = tabHost;
                mViewPager = pager;
                mTabHost.setOnTabChangedListener(this);
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }
    
            public void clearData(){
    
                mTabs.clear();
                notifyDataSetChanged();
    
            }
    
            public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
                tabSpec.setContent(new DummyTabFactory(mContext));
                String tag = tabSpec.getTag();
    
                TabInfo info = new TabInfo(tag, clss, args);
                mTabs.add(info);
    
                mTabHost.addTab(tabSpec);
    
                notifyDataSetChanged();
            }
    
            @Override
            public int getCount() {
                return mTabs.size();
            }
    
            @Override
            public Fragment getItem(int position) {
                TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
            }
    
            @Override
            public void onTabChanged(String tabId) {
                int position = mTabHost.getCurrentTab();
                mViewPager.setCurrentItem(position);
            }
    
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
            }
    
            @Override
            public void onPageSelected(int position) {
                // Unfortunately when TabHost changes the current tab, it kindly
                // also takes care of putting focus on it when not in touch mode.
                // The jerk.
                // This hack tries to prevent this from pulling focus out of our
                // ViewPager.
                TabWidget widget = mTabHost.getTabWidget();
                int oldFocusability = widget.getDescendantFocusability();
                widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
                mTabHost.setCurrentTab(position);
                widget.setDescendantFocusability(oldFocusability);
    
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
            }
        }
    
        @Override
        public void onClick(View v) {
    
    
            mTabsAdapter.clearData();
    
            mTabHost.clearAllTabs();
            //mTabsAdapter.notifyDataSetChanged();
    
            Bundle mBundleSimple=new Bundle();
            mBundleSimple.putString("data", "SimpleData");
    
            mTabsAdapter.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                    FragmentStackSupport.CountingFragment.class, mBundleSimple);
    
            Bundle mBundleContacts=new Bundle();
            mBundleContacts.putString("data", "Contacts");
    
            mTabsAdapter.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                    LoaderCursorSupport.CursorLoaderListFragment.class, mBundleContacts);
    
            Bundle mBundleCustom=new Bundle();
            mBundleCustom.putString("data", "Custom");
    
            mTabsAdapter.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                    LoaderCustomSupport.AppListFragment.class, mBundleCustom);
    
            Bundle mBundleThrottle=new Bundle();
            mBundleThrottle.putString("data", "Throttle");
    
            mTabsAdapter.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                    LoaderThrottleSupport.ThrottledLoaderListFragment.class, mBundleThrottle);
    
    
            mViewPager.setAdapter(mTabsAdapter);
    
        }
    
        @Override
        public void ClickButton(String strToken) {
    
            if(strToken.equalsIgnoreCase("OneBtn")){
    
    
                mTabsAdapter.clearData();
    
                mTabHost.clearAllTabs();
                //mTabsAdapter.notifyDataSetChanged();
    
                Bundle mBundleSimple=new Bundle();
                mBundleSimple.putString("data", "SimpleData");
    
                mTabsAdapter.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                        FragmentStackSupport.CountingFragment.class, mBundleSimple);
    
                Bundle mBundleContacts=new Bundle();
                mBundleContacts.putString("data", "SimpleData");
    
                mTabsAdapter.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                        LoaderCursorSupport.CursorLoaderListFragment.class, mBundleContacts);
    
                Bundle mBundleCustom=new Bundle();
                mBundleCustom.putString("data", "Custom");
    
                mTabsAdapter.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                        LoaderCustomSupport.AppListFragment.class, mBundleCustom);
    
                Bundle mBundleThrottle=new Bundle();
                mBundleThrottle.putString("data", "Throttle");
    
                mTabsAdapter.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                        LoaderThrottleSupport.ThrottledLoaderListFragment.class, mBundleThrottle);
    
    
                mViewPager.setAdapter(mTabsAdapter);
            }
    
        }
    }
    

    在上面的片段活动中,我进行了以下更改以重新创建适配器数据。

    1. 公开Fragments列表的清除功能,在本例中为mTabs。 2.在清除 Fragments Array 后,添加新的 Fragment 并进行所需的更改,在上面的类中,您可以看到我已经添加了带有它的 bundle 的 Fragment,并且我可以进入所有 Fragment 类。 3.在ViewPager中设置Adaper。

    下面是包含 Fragment 代码的类。

    public class FragmentStackSupport extends FragmentActivity {
        int mStackLevel = 1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.fragment_stack);
    
            // Watch for button clicks.
            Button button = (Button)findViewById(R.id.new_fragment);
            button.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    addFragmentToStack();
                }
            });
            button = (Button)findViewById(R.id.home);
            button.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    // If there is a back stack, pop it all.
                    FragmentManager fm = getSupportFragmentManager();
                    if (fm.getBackStackEntryCount() > 0) {
                        fm.popBackStack(fm.getBackStackEntryAt(0).getId(),
                                FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    }
                }
            });
    
            if (savedInstanceState == null) {
                // Do first time initialization -- add initial fragment.
                Fragment newFragment = CountingFragment.newInstance(mStackLevel);
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.add(R.id.simple_fragment, newFragment).commit();
            } else {
                mStackLevel = savedInstanceState.getInt("level");
            }
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt("level", mStackLevel);
        }
    
    
        void addFragmentToStack() {
            mStackLevel++;
    
            // Instantiate a new fragment.
            Fragment newFragment = CountingFragment.newInstance(mStackLevel);
    
            // Add the fragment to the activity, pushing this transaction
            // on to the back stack.
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.simple_fragment, newFragment);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.addToBackStack(null);
            ft.commit();
        }
    
    
    
        public static class CountingFragment extends Fragment implements OnClickListener {
            int mNum;
    
            Button mBtnOne;
    
            FragmentCallBack mFragmentCallBack;
    
            /**
             * Create a new instance of CountingFragment, providing "num"
             * as an argument.
             */
            static CountingFragment newInstance(int num) {
                CountingFragment f = new CountingFragment();
    
                // Supply num input as an argument.
                Bundle args = new Bundle();
                args.putInt("num", num);
                f.setArguments(args);
    
                return f;
            }
    
            /**
             * When creating, retrieve this instance's number from its arguments.
             */
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                mNum = getArguments() != null ? getArguments().getInt("num") : 1;
    
    
                if(getArguments()!=null){
    
                    if(getArguments().containsKey("data")){
    
                        String dataIs=getArguments().getString("data");
    
                        Log.v("LOG_TAG", "THis Tab data is  "+ dataIs );
    
    
                    }
                }
            }
    
            /**
             * The Fragment's UI is just a simple text view showing its
             * instance number.
             */
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
    
                 if(getArguments()!=null){
    
                    if(getArguments().containsKey("data")){
    
                        String dataIs=getArguments().getString("data");
    
                        Log.v("LOG_TAG", "THis Tab data is  onCreateView "+ dataIs );
    
    
                    }
                 }
    
                View v = inflater.inflate(R.layout.hello_world, container, false);
    
                TextView tv = (TextView) v.findViewById(R.id.text);
    
                mBtnOne=(Button)v.findViewById(R.id.btn_one);
    
                mBtnOne.setOnClickListener(this);
    
               tv.setText("Fragment #" + mNum);
                tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
                return v;
            }
    
            @Override
            public void onClick(View v) {
    
                try{
                    mFragmentCallBack=(FragmentCallBack) this.getActivity();
    
                    mFragmentCallBack.ClickButton("OneBtn");
    
                }catch(ClassCastException classExc){
    
                    classExc.printStackTrace();
                }
    
            }
        }
    
    }
    

    现在,当您的任何片段发生变化时,您需要创建一个接口,将回调发送到保存您的 ViewPager 的 FragmentActivity,以便您可以删除现有的 Fragment 并重新创建它。

    这是我的接口类。

    public interface FragmentCallBack {
    
    
        public void ClickButton(String strToken);
    } 
    

    希望您能了解如何在您的代码中做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多