ViewPager和片段 - 什么是存储片段状态的正确方法?

时间:2011-10-31 09:18:33

标签: android design-patterns android-fragments android-viewpager

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

修改

见下面的哑法; - )

范围

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

问题

当重新创建活动时(例如,在方向更改时),ViewPager的片段也是如此。代码(您将在下面找到)说每次创建活动时我尝试创建一个与片段相同的新ViewPager片段适配器(可能这是问题)但FragmentManager已经将所有这些片段存储在某个地方(在哪里?)并启动那些娱乐机制。因此,重新启动机制使用我的回调接口调用来调用“旧”片段的onAttach,onCreateView等,以通过Activity的实现方法启动数据。但是这个方法指向新创建的片段,该片段是通过Activity的onCreate方法创建的。

问题

也许我使用了错误的模式,但即使是Android 3 Pro也没有太多关于它的内容。所以,,给我一两拳,并指出如何以正确的方式做到这一点。非常感谢!

代码

主要活动

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 aka helper

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();
    ...
}

11 个答案:

答案 0 :(得分:441)

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

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

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

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

答案 1 :(得分:35)

我想提供一个扩展antonyt wonderful answer的解决方案,并提及覆盖FragmentPageAdapter.instantiateItem(View, int)以保存对已创建Fragments的引用,以便您可以执行此操作以后再做些工作。这也适用于FragmentStatePagerAdapter;有关详细信息,请参阅说明。


以下是一个简单的示例,说明如何获取Fragments返回的FragmentPagerAdapter的引用,该tags不依赖于{Fragments上设置的内部getItem() 1}}。关键是覆盖instantiateItem()并保存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(); } } } 而不是的参考文献。

tags

如果您更喜欢使用Fragments代替tags的类成员变量/引用,您还可以获取FragmentPagerAdapter设置的FragmentStatePagerAdapter 1}}以同样的方式: 注意:这不适用于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; }

tag

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


请勿忘记,根据您Fragments的设计,您尝试工作的null可能存在,也可能不存在,因此在使用引用之前,您必须通过FragmentStatePagerAdapter检查来解释这一点。

此外,如果相反您正在使用Fragments,那么您不希望保留对Fragment的硬性引用,因为您可能拥有其中许多和硬引用会不必要地将它们留在内存中。而是将WeakReference个引用保存在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... } 个变量而不是标准变量中。像这样:

{{1}}

答案 2 :(得分:18)

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

正如您在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")

答案 3 :(得分:16)

我想为一个稍微不同的案例提供一个替代解决方案,因为我的许多答案都会引导我进入这个主题。

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

<强>问题 - 我没有为我创建的每个片段提供唯一标识符,因此引用的唯一方法是以某种方式在Array中存储引用,以便在旋转/配置更改后恢复。

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

public class MainActivity extends FragmentActivity

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

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

每次在onCreate

中调用并恢复onSaveInstanceState时都会更新
@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生命周期的过程中,所以请注意,此方法可能存在冗余/效率低下。但它对我有用,我希望对其他案件有所帮助。

答案 4 :(得分:8)

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

@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 ) );  

答案 5 :(得分:4)

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

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

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

答案 6 :(得分:2)

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

确保在致电ViewPager.setOffscreenPageLimit()

之前致电ViewPager.setAdapeter(fragmentStatePagerAdapter)

在致电ViewPager.setOffscreenPageLimit()时... ViewPager将立即查看其适配器并尝试获取其片段。这可能发生在ViewPager有机会从savedInstanceState恢复片段之前(因此创建无法从SavedInstanceState重新初始化的新片段,因为它们是新的)。

答案 7 :(得分:0)

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

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

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();
    }
} 

这个帖子的整个问题是获得&#34; old&#34;的引用。碎片,所以我在活动的创建中使用了这段代码。

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

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

答案 8 :(得分:0)

要在方向更改后获取片段,您必须使用.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));

答案 9 :(得分:0)

有一些不同的意见,而不是自己存储碎片,而只是将其留给FragmentManager,当您需要对碎片进行操作时,可以在FragmentManager中寻找它们:

//make sure you have the right FragmentManager 
//getSupportFragmentManager or getChildFragmentManager depending on what you are using to manage this stack of fragments
List<Fragment> fragments = fragmentManager.getFragments();
if(fragments != null) {
   int count = fragments.size();
   for (int x = 0; x < count; x++) {
       Fragment fragment = fragments.get(x);
       //check if this is the fragment we want, 
       //it may be some other inspection, tag etc.
       if (fragment instanceof MyFragment) {
           //do whatever we need to do with it
       }
   }
}

如果您有很多分片,而instanceof检查的成本可能不是您想要的,但是请记住,FragmentManager已经保留了分片的账目。

答案 10 :(得分:-29)

添加:

   @SuppressLint("ValidFragment")
在你上课之前

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

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