片段似乎非常适合将 UI 逻辑分离到某些模块中。但与 ViewPager
一起,它的生命周期对我来说仍然是模糊的。所以非常需要上师的思想!
编辑
请参阅下面的愚蠢解决方案;-)
范围
主要活动有一个带有片段的 ViewPager
。这些片段可以为其他(子主)活动实现一些不同的逻辑,因此片段的数据通过活动内部的回调接口填充。首次启动时一切正常,但是!...
问题
当 Activity 重新创建时(例如,在方向改变时),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 又名助手
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();
...
}
当 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)
并在返回之前保存对从 super 调用返回的片段的引用(如果已经存在,它具有查找片段的逻辑)。
如需更全面的图片,请查看 FragmentPagerAdapter(短)和 ViewPager(长)的一些来源。
我想提供一个扩展 antonyt
的 wonderful 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();
}
}
}
或如果您更喜欢使用 tags
而不是类成员变量/对 Fragments
的引用,您也可以以相同的方式获取 FragmentPagerAdapter
设置的 tags
:注意:此不适用于 FragmentStatePagerAdapter
,因为它在创建 Fragments
时没有设置 tags
。
@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 来检索它们。这样,即使 tag
在 SupportLibrary
的未来版本中发生更改,您仍然是安全的。
不要忘记,根据您的 Activity
的设计,您尝试使用的 Fragments
可能存在也可能不存在,因此您必须通过执行 { 3} 在使用您的参考资料之前进行检查。
另外,如果您正在使用 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...
}
FragmetPagerAdapter
怎么样?这是错误的吗,因为它可能会绕过在 FragmentPagerAdapter
中重复使用已添加的片段
instantiateItem()
是要走的路;这有助于我处理屏幕旋转,并在 Activity 和 Adapter 恢复后检索我现有的 Fragment 实例;我在代码中留下了自己的注释作为提醒:旋转后,getItem()
未被调用;只有这个方法 instantiateItem()
被调用。 instantiateItem()
的超级实现实际上在旋转后重新附加片段(根据需要),而不是实例化新实例!
Fragment createdFragment = (Fragment) super.instantiateItem..
上得到空指针。
我为您的问题找到了另一个相对简单的解决方案。
正如您从 FragmentPagerAdapter source code 中看到的,由 FragmentPagerAdapter
管理的片段存储在 FragmentManager
中使用以下生成的标记下:
String tag="android:switcher:" + viewId + ":" + index;
viewId
是 container.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);
如果想和这个fragment通信,可以从FragmentManager
中获取if,如:
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
tag
的解决方案的人,请考虑尝试 my answer。
我想为可能略有不同的情况提供一个替代解决方案,因为我对答案的许多搜索一直把我带到这个线程。
我的情况 - 我正在动态创建/添加页面并将它们滑动到 ViewPager 中,但是当旋转 (onConfigurationChange) 时,我最终会得到一个新页面,因为当然会再次调用 OnCreate。但我想保留对轮换之前创建的所有页面的引用。
问题 - 我创建的每个片段都没有唯一标识符,因此引用的唯一方法是以某种方式将引用存储在数组中,以便在轮换/配置更改后恢复。
解决方法 - 关键概念是让 Activity(显示 Fragments)也管理对现有 Fragments 的引用数组,因为此 Activity 可以利用 onSaveInstanceState 中的 Bundle
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 生命周期,因此需要注意的是,这种方法可能存在冗余/效率低下。但这对我有用,我希望可能对其他与我类似的情况有所帮助。
我的解决方案非常粗鲁但有效:作为从保留数据动态创建的片段,我只需在调用 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 ) );
那是什么BasePagerAdapter
?您应该使用标准寻呼机适配器之一 - FragmentPagerAdapter
或 FragmentStatePagerAdapter
,具体取决于您是否希望 ViewPager
不再需要的片段被保留(前者)或保存其状态(后者)并在需要时重新创建。
使用 ViewPager
的示例代码可以在 here 中找到
确实,跨活动实例的视图分页器中的片段管理有点复杂,因为框架中的 FragmentManager
负责保存状态并恢复分页器创建的任何活动片段。所有这一切真正意味着适配器在初始化时需要确保它与任何已恢复的片段重新连接。您可以查看 FragmentPagerAdapter
或 FragmentStatePagerAdapter
的代码以了解这是如何完成的。
如果有人在他们的 FragmentStatePagerAdapter 无法正确恢复其片段的状态时遇到问题......即...... FragmentStatePagerAdapter 正在创建新的片段,而不是从状态中恢复它们......
确保在致电 ViewPager.setAdapter(fragmentStatePagerAdapter)
之前致电 ViewPager.setOffscreenPageLimit()
调用 ViewPager.setOffscreenPageLimit()
...ViewPager 将立即查看其适配器并尝试获取其片段。这可能发生在 ViewPager 有机会从 savedInstanceState 恢复 Fragments 之前(从而创建新的 Fragments,因为它们是新的,所以不能从 SavedInstanceState 重新初始化)。
我想出了这个简单而优雅的解决方案。它假定活动负责创建片段,而适配器只是为它们服务。
这是适配器的代码(这里没什么奇怪的,除了 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);
}
}
}
当然,如果需要,您可以进一步微调此代码,例如确保片段是特定类的实例。
要在方向更改后获取片段,您必须使用 .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));
有点不同的意见,而不是自己存储 Fragment,只需将其留给 FragmentManager,当您需要对 Fragment 执行某些操作时,请在 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
}
}
}
如果你有很多 Fragment 并且 instanceof 检查的成本可能不是你想要的,但是记住 FragmentManager 已经记录了 Fragment 是一件好事。
添加:
@SuppressLint("ValidFragment")
在你上课之前。
它不起作用做这样的事情:
@SuppressLint({ "ValidFragment", "HandlerLeak" })
FragmentPageAdapter.instantiateItem(View, int)
移动。终于修复了一个长期存在的错误,它只出现在轮换/配置更改中,让我发疯......FragmentPageAdapter.instantiateItem(ViewGroup, int)
而不是FragmentPageAdapter.instantiateItem(View, int)
。onDetach()
还是别的什么?