解释
最近,我一直在与碎片和viewpager进行大量的斗争。
我发现ViewPager可以保存你想要的任意多的片段。当它首次实例化时,根据类型(FragmentStatePagerAdapter
vsFragmentPagerAdapter
FragmentPagerAdapter和FragmentStatePagerAdapter之间的差异),它将创建所有片段或只创建“需要的”片段。
class MyFragment extends Fragment
{
private Context context;
private doThingsAfterAttach()
{
getActivity(); //this is null.
null != context; //TRUE
}
@Override
public onAttach( Activity activity )
{
context = activity;
doThingsAfterAttach();
}
}
您可以看到,getactivity()
返回null,尽管您是在onattach
被触发后调用此方法的。
如果您决定将保留的上下文强制转换为活动,以执行findviewbyid
任务,您将看到您试图查找的视图为null,这意味着无法找到/不存在。
发行
谢谢大家,在这里我准备回答大家的问题。
谢了。
注意:这是一篇冗长且可能令人厌烦的文章
你的查看页问题并不新鲜。别难过。我们都经历过似乎是一个新范例的神奇解决方案(我将用斜体表示new,因为它在当时并不一定是新的)。添加了对片段的支持(通过您提到的状态和无状态适配器),事情很快变得更加有趣。
我不打算详细说明适配器是好的还是烦人的(您可以得出自己的结论),或者为什么适配器(以及小部件本身)缺乏非常基本的东西,没有人知道Android开发人员在为这些东西公开公共API时是怎么想的。
所以…取景器需要一个适配器。适配器负责向视图页提供视图。因此,虽然ViewPager是一个理解触摸、拖动、抛出、绘制、测量等内容的视图,但它实际上希望适配器提供要显示的数据。(这是一个巨大的简化)。
这里我们有两种类型的适配器,它们知道如何处理片段。一个保持一种状态,另一个不。意思是一个并没有真正释放任何东西(碎片PagerAdapter)和一个确实释放了它的碎片(碎片StatePagerAdapter)…但是等等…在这个上下文中什么是“释放”?
事实证明,碎片并不真的存在于一个自由的世界中,它们由一个FragmentManager控制,他确保它们不会迟到,并决定何时释放它们。这是一个连适配器都不能覆盖的规则!所以他们无论如何都必须向这个碎片管理器报告。您可以看出,适配器必须与这个FragmentManager对话,因为它必须在构造函数中接收一个!
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
好的,谢谢明显先生!
实际上,FragmentManager是一个静态类,您不创建它,只从活动中获取它。
现在想想controller的FragmentManager,它保留对您的片段的引用,即使在您离开它们很久之后也是如此。它知道如何使它们返回,它帮助它们在配置更改(例如,旋转)时保存它们的状态,它保存它们的一堆/堆栈,知道它们可以按什么顺序弹出,并执行所有这些操作,传递必须提交的碎片事务,很像关系数据库事务。
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
和对FragmentManager的引用:
private final FragmentManager mFragmentManager;
毫不奇怪,FragmentPagerAdapter没有片断列表,也没有保存状态列表,它只是让FragmentManager完成它的工作。
因此,让我们首先看看“state”寻呼机适配器,看看在销毁一个片段的时候会做什么…
1 @Override
2 public void destroyItem(ViewGroup container, int position, Object object) {
3 Fragment fragment = (Fragment)object;
4 if (mCurTransaction == null) {
5 mCurTransaction = mFragmentManager.beginTransaction();
6 }
7 if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
8 + " v=" + ((Fragment)object).getView());
9 while (mSavedState.size() <= position) {
10 mSavedState.add(null);
11 }
12 mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
13 mFragments.set(position, null);
14 mCurTransaction.remove(fragment);
15 }
第14行将此添加到片段的Manager事务中,以便FragmentManager知道要做什么。
(注意:当您动态添加/更改/删除片段时,在ViewPager中有一个模糊的bug,我将在最后链接到问题/解决方案)。
当您将片段添加到ViewPager时,过程相对类似(请参见instantiateItem()
方法…
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
最后,它继续添加新收到的片段:
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
它必须添加null填充以使数组达到准确的大小,当然还使用了FragmentTransaction。
到目前为止,这个故事的寓意是,适配器保留了自己的东西集合,但通过让老板(又名:碎片管理器)知道他在控制,这让他很高兴。
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
还可以查看其中的removeFragment()
方法,该方法最终调用moveTostate()
方法。
够了…我什么时候可以调用getActivity(),而不在片段中获得null?
好的,所以你提供了一个你想做的例子。
public interface FragmentInterface {
void onBecameVisible();
}
public Fragment YourFragment implements FragmentInterface {
然后你有一个:
@Override
public void onBecameVisible() {
if (getActivity() != null && !getActivity().isFinishing()) {
// do something with your Activity -which should also implement an interface!-
}
}
谁叫onbecamevisible?
活动中的viewPager.onPageChangelistener():
public void onPageSelected(final int i) {
FragmentInterface fragment = (FragmentInterface) mPagerAdapter.instantiateItem(mViewPager, i);
if (fragment != null) {
fragment.onBecameVisible();
}
}
我在一个详细视图中使用ViewPager和FragmentPagerAdapter。这意味着我有一个项目列表,一个屏幕显示单个项目的细节。但用户可以左右滑动来浏览所有项目。这遵循了谷歌滑动视图的指导方针。 但是我想知道一件事。在ListView中,每一行的视图都会被重用。一旦一行从屏幕上滚动出来,它就会被重用为绑定到ListView的适配器的getView方法的转换器视图参数。但是这种重用行为似乎
MainActivity(扩展了fragmentActivity)有listview,它调用listviewadapter,其中有一个带有ViewpagerAdapter的ViewPager。现在,如果我需要在ViewPager中生成5个片段,如何将getFragmentManager()传递给适配器。 MainActivity[fragmentActivity]---->Listview----
我需要将ViewPager放置在一个片段内部,但我有两个片段,片段1是我的菜单,片段2我想用作ViewPagerIndicator。 但一个碎片不能再有另一个碎片...我该怎么做呢?
我可以将谷歌地图加载到活动中的Android片段中。这一直运行良好。 但现在我想使用ViewPager在视图之间导航(class
我有以下布局 一切正常,但我想用一个片段替换浏览器 这不是重新调整ViewPager的间距,我该怎么办???
我正在使用嵌套片段,当我按下时,我面临问题。 流量: 这是我的应用程序的结构。其中C、D、E、F是子片段,未添加到后堆栈中。D包含列表片段,从D中我称为B。但当我从B中按回来时,我想再次使用最后选定位置的D。我在后堆栈中添加了A和B。我怎样才能做到这一点。给我提供一些解决方案。我回忆起D,但选择的位置总是在变化。