首页 文章

ViewPager和片段 - 's the right way to store fragment'的状态是什么?

提问于
浏览
466

片段似乎非常适合将UI逻辑分离为某些模块 . 但随着 ViewPager ,它的生命周期对我来说仍然是迷雾 . 因此迫切需要大师的想法!

编辑

见下面的哑解决方案;-)

范围

主要活动有一个 ViewPager 与片段 . 这些片段可以为其他(子域)活动实现一些不同的逻辑,因此片段的数据通过活动内部的回调接口填充 . 第一次发布时一切正常,但是!...

问题

当重新创建活动时(例如,在方向更改时),所以 ViewPager 's fragments. The code (you' ll在下面找到)表示每次创建活动时我尝试创建一个与片段相同的新 ViewPager 片段适配器(可能这是问题)但FragmentManager已经将所有这些片段存储在某处(其中?)并为这些片段启动娱乐机制 . 因此,重新创建机制会调用"old" fragment _158754实现的方法 . 但是这个方法指向通过Activity的onCreate方法创建的新创建的片段 .

问题

也许我对它有很多了解 . 所以, please ,给我一两拳,并指出如何以正确的方式做到这一点 . 非常感谢!

代码

主要活动

public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {

private MessagesFragment mMessagesFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Logger.d("Dash onCreate");
    super.onCreate(savedInstanceState);

    setContentView(R.layout.viewpager_container);
    new DefaultToolbar(this);

    // create fragments to use
    mMessagesFragment = new MessagesFragment();
    mStreamsFragment = new StreamsFragment();

    // set titles and fragments for view pager
    Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();
    screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());
    screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);

    // instantiate view pager via adapter
    mPager = (ViewPager) findViewById(R.id.viewpager_pager);
    mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());
    mPager.setAdapter(mPagerAdapter);

    // set title indicator
    TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);
    indicator.setViewPager(mPager, 1);

}

/* set of fragments callback interface implementations */

@Override
public void onMessageInitialisation() {

    Logger.d("Dash onMessageInitialisation");
    if (mMessagesFragment != null)
        mMessagesFragment.loadLastMessages();
}

@Override
public void onMessageSelected(Message selectedMessage) {

    Intent intent = new Intent(this, StreamActivity.class);
    intent.putExtra(Message.class.getName(), selectedMessage);
    startActivity(intent);
}

BasePagerActivity又名助手

public class BasePagerActivity extends FragmentActivity {

BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}

适配器

public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {

private Map<String, Fragment> mScreens;

public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) {

    super(fm);
    this.mScreens = screenMap;
}

@Override
public Fragment getItem(int position) {

    return mScreens.values().toArray(new Fragment[mScreens.size()])[position];
}

@Override
public int getCount() {

    return mScreens.size();
}

@Override
public String getTitle(int position) {

    return mScreens.keySet().toArray(new String[mScreens.size()])[position];
}

// hack. we don't want to destroy our fragments and re-initiate them after
@Override
public void destroyItem(View container, int position, Object object) {

    // TODO Auto-generated method stub
}

}

分段

public class MessagesFragment extends ListFragment {

private boolean mIsLastMessages;

private List<Message> mMessagesList;
private MessageArrayAdapter mAdapter;

private LoadMessagesTask mLoadMessagesTask;
private OnMessageListActionListener mListener;

// define callback interface
public interface OnMessageListActionListener {
    public void onMessageInitialisation();
    public void onMessageSelected(Message selectedMessage);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    // setting callback
    mListener = (OnMessageListActionListener) activity;
    mIsLastMessages = activity instanceof DashboardActivity;

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    inflater.inflate(R.layout.fragment_listview, container);
    mProgressView = inflater.inflate(R.layout.listrow_progress, null);
    mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);
    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // instantiate loading task
    mLoadMessagesTask = new LoadMessagesTask();

    // instantiate list of messages
    mMessagesList = new ArrayList<Message>();
    mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);
    setListAdapter(mAdapter);
}

@Override
public void onResume() {
    mListener.onMessageInitialisation();
    super.onResume();
}

public void onListItemClick(ListView l, View v, int position, long id) {
    Message selectedMessage = (Message) getListAdapter().getItem(position);
    mListener.onMessageSelected(selectedMessage);
    super.onListItemClick(l, v, position, id);
}

/* public methods to load messages from host acitivity, etc... */
}

解决方案

愚蠢的解决方案是使用putFragment将片段保存在onSaveInstanceState(主机Activity)中,并通过getFragment将它们放在onCreate中 . 但我仍然有一种奇怪的感觉,事情不应该像那样......请参阅下面的代码:

@Override
protected void onSaveInstanceState(Bundle outState) {

    super.onSaveInstanceState(outState);
    getSupportFragmentManager()
            .putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);
}

protected void onCreate(Bundle savedInstanceState) {
    Logger.d("Dash onCreate");
    super.onCreate(savedInstanceState);

    ...
    // create fragments to use
    if (savedInstanceState != null) {
        mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment(
                savedInstanceState, MessagesFragment.class.getName());
                StreamsFragment.class.getName());
    }
    if (mMessagesFragment == null)
        mMessagesFragment = new MessagesFragment();
    ...
}

10 回答

  • 35

    那是什么 BasePagerAdapter ?您应该使用标准的寻呼机适配器之一 - FragmentPagerAdapterFragmentStatePagerAdapter ,具体取决于您是否希望 ViewPager 不再需要的碎片保留(前者)或保存其状态(后者)并重新使用 - 如果需要再创建 .

    使用 ViewPager 的示例代码可以找到here

    确实,跨越活动实例的视图分页器中的片段管理有点复杂,因为框架中的 FragmentManager 负责保存状态并恢复寻呼机所做的任何活动片段 . 所有这些真正意味着初始化时适配器需要确保它与任何已恢复的片段重新连接 . 您可以查看 FragmentPagerAdapterFragmentStatePagerAdapter 的代码以了解如何完成此操作 .

  • 16

    FragmentPagerAdapter 将片段添加到FragmentManager时,它会根据片段放置的特定位置使用特殊标记 . 仅当该位置的片段不存在时才会调用 FragmentPagerAdapter.getItem(int position) . 旋转后,Android会注意到它已经为这个特定位置创建/保存了一个片段,所以它只是尝试用 FragmentManager.findFragmentByTag() 重新连接它,而不是创建一个新的 . 使用 FragmentPagerAdapter 时所有这些都是免费的,这就是为什么通常在 getItem(int) 方法中使用片段初始化代码 .

    即使我们没有使用 FragmentPagerAdapter ,在 Activity.onCreate(Bundle) 中每次创建一个新片段也不是一个好主意 . 正如您所注意到的,当片段添加到FragmentManager时,它将在旋转后为您重新创建,无需再次添加 . 在处理片段时,这样做是导致错误的常见原因 .

    处理片段时常用的方法是:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        ...
    
        CustomFragment fragment;
        if (savedInstanceState != null) {
            fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag");
        } else {
            fragment = new CustomFragment();
            getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit(); 
        }
    
        ...
    
    }
    

    使用 FragmentPagerAdapter 时,我们将片段管理放弃到适配器,而不必执行上述步骤 . 默认情况下,它只会在当前位置的前面和后面预加载一个Fragment(虽然它不会破坏它们,除非你使用 FragmentStatePagerAdapter ) . 这由ViewPager.setOffscreenPageLimit(int)控制 . 因此,不能保证在适配器外部的片段上直接调用方法是有效的,因为它们甚至可能不存在 .

    简而言之,您使用 putFragment 之后能够获得参考的解决方案并不是那么疯狂,并且与正常使用片段的方式不同(上图) . 否则很难获得参考,因为片段是由适配器添加的,而不是您个人添加的 . 只需确保 offscreenPageLimit 足够高,可以随时加载您想要的碎片,因为您依赖它存在 . 这绕过了ViewPager的延迟加载功能,但似乎是您对应用程序的期望 .

    另一种方法是覆盖 FragmentPageAdapter.instantiateItem(View, int) 并在返回之前保存对超级调用返回的片段的引用(它具有查找片段的逻辑,如果已经存在) .

    要获得更全面的图片,请查看FragmentPagerAdapter(短)和ViewPager(长)的一些来源 .

  • 8

    如果有任何人遇到问题,他们的FragmentStatePagerAdapter没有正确恢复其片段的状态...即... FragmentStatePagerAdapter正在创建新的片段而不是从州恢复它们......

    确保在致电 ViewPager.setAdapeter(fragmentStatePagerAdapter) 之前致电 ViewPager.setOffscreenPageLimit()

    在调用 ViewPager.setOffscreenPageLimit() 时... ViewPager将 immediately 查看其适配器并尝试获取其片段 . 这可能发生在ViewPager有机会从savedInstanceState恢复片段之前(从而创建新的片段,可以重新创建) .

  • 435

    加:

    @SuppressLint("ValidFragment")
    

    在你上课之前 .

    它不起作用做这样的事情:

    @SuppressLint({ "ValidFragment", "HandlerLeak" })
    
  • 17

    要在方向更改后获取片段,您必须使用.getTag() .

    getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager)
    

    为了更多的处理,我为我的PageAdapter编写了自己的ArrayList,以便在任何位置通过viewPagerId和FragmentClass获取片段:

    public class MyPageAdapter extends FragmentPagerAdapter implements Serializable {
    private final String logTAG = MyPageAdapter.class.getName() + ".";
    
    private ArrayList<MyPageBuilder> fragmentPages;
    
    public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) {
        super(fm);
        fragmentPages = fragments;
    }
    
    @Override
    public Fragment getItem(int position) {
        return this.fragmentPages.get(position).getFragment();
    }
    
    @Override
    public CharSequence getPageTitle(int position) {
        return this.fragmentPages.get(position).getPageTitle();
    }
    
    @Override
    public int getCount() {
        return this.fragmentPages.size();
    }
    
    
    public int getItemPosition(Object object) {
        //benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden
    
        Log.d(logTAG, object.getClass().getName());
        return POSITION_NONE;
    }
    
    public Fragment getFragment(int position) {
        return getItem(position);
    }
    
    public String getTag(int position, int viewPagerId) {
        //getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem())
    
        return "android:switcher:" + viewPagerId + ":" + position;
    }
    
    public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
        return new MyPageBuilder(pageTitle, icon, selectedIcon, frag);
    }
    
    
    public static class MyPageBuilder {
    
        private Fragment fragment;
    
        public Fragment getFragment() {
            return fragment;
        }
    
        public void setFragment(Fragment fragment) {
            this.fragment = fragment;
        }
    
        private String pageTitle;
    
        public String getPageTitle() {
            return pageTitle;
        }
    
        public void setPageTitle(String pageTitle) {
            this.pageTitle = pageTitle;
        }
    
        private int icon;
    
        public int getIconUnselected() {
            return icon;
        }
    
        public void setIconUnselected(int iconUnselected) {
            this.icon = iconUnselected;
        }
    
        private int iconSelected;
    
        public int getIconSelected() {
            return iconSelected;
        }
    
        public void setIconSelected(int iconSelected) {
            this.iconSelected = iconSelected;
        }
    
        public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
            this.pageTitle = pageTitle;
            this.icon = icon;
            this.iconSelected = selectedIcon;
            this.fragment = frag;
        }
    }
    
    public static class MyPageArrayList extends ArrayList<MyPageBuilder> {
        private final String logTAG = MyPageArrayList.class.getName() + ".";
    
        public MyPageBuilder get(Class cls) {
            // Fragment über FragmentClass holen
            for (MyPageBuilder item : this) {
                if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
                    return super.get(indexOf(item));
                }
            }
            return null;
        }
    
        public String getTag(int viewPagerId, Class cls) {
            // Tag des Fragment unabhängig vom State z.B. nach bei Orientation change
            for (MyPageBuilder item : this) {
                if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
                    return "android:switcher:" + viewPagerId + ":" + indexOf(item);
                }
            }
            return null;
        }
    }
    

    所以只需创建一个包含片段的MyPageArrayList:

    myFragPages = new MyPageAdapter.MyPageArrayList();
    
        myFragPages.add(new MyPageAdapter.MyPageBuilder(
                getString(R.string.widget_config_data_frag),
                R.drawable.ic_sd_storage_24dp,
                R.drawable.ic_sd_storage_selected_24dp,
                new WidgetDataFrag()));
    
        myFragPages.add(new MyPageAdapter.MyPageBuilder(
                getString(R.string.widget_config_color_frag),
                R.drawable.ic_color_24dp,
                R.drawable.ic_color_selected_24dp,
                new WidgetColorFrag()));
    
        myFragPages.add(new MyPageAdapter.MyPageBuilder(
                getString(R.string.widget_config_textsize_frag),
                R.drawable.ic_settings_widget_24dp,
                R.drawable.ic_settings_selected_24dp,
                new WidgetTextSizeFrag()));
    

    并将它们添加到viewPager:

    mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages);
        myViewPager.setAdapter(mAdapter);
    

    在此之后,您可以通过使用其类来获取方向更改正确的片段:

    WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
                .findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
    
  • 4

    我找到了另一个相对简单的解决方案 .

    正如您在FragmentPagerAdapter source code中看到的那样,由 FragmentPagerAdapter 管理的片段存储在 FragmentManager 下使用以下标签生成的标签:

    String tag="android:switcher:" + viewId + ":" + index;
    

    viewIdcontainer.getId()container 是你的 ViewPager 实例 . index 是片段的位置 . 因此,您可以将对象ID保存到 outState

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("viewpagerid" , mViewPager.getId() );
    }
    
    @Override
        protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main);
        if (savedInstanceState != null)
            viewpagerid=savedInstanceState.getInt("viewpagerid", -1 );  
    
        MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this);        
        mViewPager = (ViewPager) findViewById(R.id.pager);
        if (viewpagerid != -1 ){
            mViewPager.setId(viewpagerid);
        }else{
            viewpagerid=mViewPager.getId();
        }
        mViewPager.setAdapter(titleAdapter);
    

    如果您想与此片段进行通信,可以从 FragmentManager 获取,例如:

    getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
    
  • 0

    我想为一个稍微不同的案例提供一个替代解决方案,因为我的许多搜索答案一直引导我到这个线程 .

    My case - 我正在动态创建/添加页面并将它们滑动到ViewPager中,但是当旋转(onConfigurationChange)时,我最终会得到一个新页面,因为当然会再次调用OnCreate . 但我想继续引用旋转之前创建的所有页面 .

    Problem - 我没有为我创建的每个片段提供唯一标识符,因此引用的唯一方法是以某种方式存储在旋转/配置更改后要恢复的数组中的引用 .

    Workaround - 关键概念是让Activity(显示片段)也管理对现有片段的引用数组,因为此活动可以利用onSaveInstanceState中的Bundles

    public class MainActivity extends FragmentActivity
    

    因此,在此活动中,我声明一个私人成员来跟踪打开的页面

    private List<Fragment> retainedPages = new ArrayList<Fragment>();
    

    每次onSaveInstanceState都会在onCreate中调用和恢复时更新

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        retainedPages = _adapter.exportList();
        outState.putSerializable("retainedPages", (Serializable) retainedPages);
        super.onSaveInstanceState(outState);
    }
    

    ...所以一旦存储,就可以检索到......

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        if (savedInstanceState != null) {
            retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages");
        }
        _mViewPager = (CustomViewPager) findViewById(R.id.viewPager);
        _adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager());
        if (retainedPages.size() > 0) {
            _adapter.importList(retainedPages);
        }
        _mViewPager.setAdapter(_adapter);
        _mViewPager.setCurrentItem(_adapter.getCount()-1);
    }
    

    这些是对主要活动的必要更改,因此我需要FragmentPagerAdapter中的成员和方法才能使其工作,因此

    public class ViewPagerAdapter extends FragmentPagerAdapter
    

    一个相同的构造(如上面MainActivity中所示)

    private List<Fragment> _pages = new ArrayList<Fragment>();
    

    并且这种方法特别支持这种同步(如上面onSaveInstanceState中所使用的)

    public List<Fragment> exportList() {
        return _pages;
    }
    
    public void importList(List<Fragment> savedPages) {
        _pages = savedPages;
    }
    

    最后,在片段类中

    public class CustomFragment extends Fragment
    

    为了使所有这些工作,首先有两个变化

    public class CustomFragment extends Fragment implements Serializable
    

    然后将其添加到onCreate中,以便不破坏碎片

    setRetainInstance(true);
    

    我仍然在围绕Fragments和Android生命周期进行整理,所以请注意,这种方法可能存在冗余/效率低下 . 但它适用于我,我希望可能对其他类似我的案例有帮助 .

  • 2

    我想出了这个简单而优雅的解决方案 . 它假定活动负责创建Fragments,而Adapter只是为它们提供服务 .

    这是适配器的代码(这里没什么奇怪的,除了 mFragments 是Activity维护的片段列表这一事实)

    class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
    
        public MyFragmentPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
            return mFragments.get(position);
        }
    
        @Override
        public int getCount() {
            return mFragments.size();
        }
    
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            TabFragment fragment = (TabFragment)mFragments.get(position);
            return fragment.getTitle();
        }
    }
    

    这个线程的整个问题是得到“旧”片段的引用,所以我在Activity的onCreate中使用了这个代码 .

    if (savedInstanceState!=null) {
            if (getSupportFragmentManager().getFragments()!=null) {
                for (Fragment fragment : getSupportFragmentManager().getFragments()) {
                    mFragments.add(fragment);
                }
            }
        }
    

    当然,如果需要,您可以进一步微调此代码,例如确保片段是特定类的实例 .

  • -29

    我想提供一个扩展 antonytwonderful answer的解决方案,并提及覆盖 FragmentPageAdapter.instantiateItem(View, int) 来保存对创建 Fragments 的引用,以便您以后可以对它们进行处理 . 这也适用于 FragmentStatePagerAdapter ;请参阅说明了解详情 .


    这是一个简单的示例,说明如何获取 FragmentPagerAdapter 返回的 Fragments 的引用,该引用不依赖于 Fragments 上设置的内部 tags . 关键是覆盖instantiateItem()并在那里保存引用而不是 getItem() .

    public class SomeActivity extends Activity {
        private FragmentA m1stFragment;
        private FragmentB m2ndFragment;
    
        // other code in your Activity...
    
        private class CustomPagerAdapter extends FragmentPagerAdapter {
            // other code in your custom FragmentPagerAdapter...
    
            public CustomPagerAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public Fragment getItem(int position) {
                // Do NOT try to save references to the Fragments in getItem(),
                // because getItem() is not always called. If the Fragment
                // was already created then it will be retrieved from the FragmentManger
                // and not here (i.e. getItem() won't be called again).
                switch (position) {
                    case 0:
                        return new FragmentA();
                    case 1:
                        return new FragmentB();
                    default:
                        // This should never happen. Always account for each position above
                        return null;
                }
            }
    
            // Here we can finally safely save a reference to the created
            // Fragment, no matter where it came from (either getItem() or
            // FragmentManger). Simply save the returned Fragment from
            // super.instantiateItem() into an appropriate reference depending
            // on the ViewPager position.
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
                // save the appropriate reference depending on position
                switch (position) {
                    case 0:
                        m1stFragment = (FragmentA) createdFragment;
                        break;
                    case 1:
                        m2ndFragment = (FragmentB) createdFragment;
                        break;
                }
                return createdFragment;
            }
        }
    
        public void someMethod() {
            // do work on the referenced Fragments, but first check if they
            // even exist yet, otherwise you'll get an NPE.
    
            if (m1stFragment != null) {
                // m1stFragment.doWork();
            }
    
            if (m2ndFragment != null) {
                // m2ndFragment.doSomeWorkToo();
            }
        }
    }
    

    or 如果您更喜欢使用 tags 而不是类成员变量/对 Fragments 的引用,您也可以通过 FragmentPagerAdapter 以相同方式获取 tags :注意:这不适用于 FragmentStatePagerAdapter ,因为它在创建时未设置 tags 它的 Fragments .

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
        // get the tags set by FragmentPagerAdapter
        switch (position) {
            case 0:
                String firstTag = createdFragment.getTag();
                break;
            case 1:
                String secondTag = createdFragment.getTag();
                break;
        }
        // ... save the tags somewhere so you can reference them later
        return createdFragment;
    }
    

    请注意,此方法不依赖于模仿 FragmentPagerAdapter 设置的内部 tag ,而是使用适当的API来检索它们 . 这种方式即使 SupportLibrary 的未来版本中的 tag 更改,您仍然是安全的 .


    Don't forget 取决于设计您正在尝试工作的 Activity 可能存在或者可能不存在,因此您必须在使用引用之前通过 null 检查来解释这一点 .

    Also, if instead 你正在使用 FragmentStatePagerAdapter ,那么你不想保留对你的 Fragments 的硬引用,因为你可能有很多这样的引用,硬引用会不必要地将它们保存在内存中 . 而是在 WeakReference 变量中保存 Fragment 引用而不是标准变量 . 像这样:

    WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
    // ...and access them like so
    Fragment firstFragment = m1stFragment.get();
    if (firstFragment != null) {
        // reference hasn't been cleared yet; do work...
    }
    
  • 0

    我的解决方案非常粗鲁但有效:作为我从保留数据动态创建的片段,我只需在调用 super.onSaveInstanceState() 之前删除 PageAdapter 中的所有片段,然后在创建活动时重新创建它们:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("viewpagerpos", mViewPager.getCurrentItem() );
        mSectionsPagerAdapter.removeAllfragments();
        super.onSaveInstanceState(outState);
    }
    

    您无法在 onDestroy() 中删除它们,否则会出现此异常:

    java.lang.IllegalStateException: onSaveInstanceState 后无法执行此操作

    这里是页面适配器中的代码:

    public void removeAllfragments()
    {
        if ( mFragmentList != null ) {
            for ( Fragment fragment : mFragmentList ) {
                mFm.beginTransaction().remove(fragment).commit();
            }
            mFragmentList.clear();
            notifyDataSetChanged();
        }
    }
    

    在创建片段后,我只保存当前页面并在 onCreate() 中恢复它 .

    if (savedInstanceState != null)
        mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) );
    

相关问题