在 ViewPager 中未使用 Fragment 调用 onCreateView
Posted
技术标签:
【中文标题】在 ViewPager 中未使用 Fragment 调用 onCreateView【英文标题】:onCreateView not called with Fragment in ViewPager 【发布时间】:2012-02-12 06:08:18 【问题描述】:我使用 ACL 中的 ViewPager
来显示几个 Fragment
s。起初,这些 Fragments 中的所有 ListFragment
s 都包含一个列表。我试图模仿一个 2 列的表,因此列表中的每个元素都包含另一个包含两个对象的列表。我希望每个单元格都可以长按(而不是整个列表项),因此我实现了自己的 ColumnLayout(也许它应该称为 CellLayout)。每个列表项包含两个可长按的 ColumnLayout,并实现 getContextMenuInfo()
以返回有关长按哪个实体的信息。此方法查找 ViewPager,请求当前片段,然后调用片段以从长按视图返回实体 id。为了获得正确的行,片段需要做:
getListView().getPositionForView(v)
问题就从这里开始。有时getListView()
抛出IllegalStateException
说“尚未创建内容视图”。 IE。 onCreateView(...)
尚未被调用。这仅在应用程序恢复时才会发生。今天,我设法通过在我的 Galaxy Nexus 上启用“设置”>“开发人员”选项中的“不保留活动”选项来重现该问题。我启动应用程序,按主页,然后从最近的应用程序菜单重新打开应用程序,现在,如果我长按列表视图中的任何单元格,则会引发此异常。通过一些调试输出,我设法验证从未调用过 onCreateView。这有点奇怪,因为整个 ViewPager 及其 Fragment 及其 ListView 及其单元格项都被绘制了!
我在 #android-dev 上被告知 ACL 中的 ListFragment
不支持自定义布局,因此我重新实现了我的 android.support.v4.app.Fragment
而不使用 ListFragment
但这没有帮助。
简短总结:我有一个自定义布局,它处理长按布局的事件,目的是创建一个 MenuInfo
对象,其中包含有关按下的单元格中实体的信息。为了找到布局中包含的实体,最终会调用listview.getPositionForView(View v)
,有时会导致IllegalStateException
。
这是我的自定义布局(也许有一种比在视图层次结构中挖掘更简单的方法来获取ViewPager
):
package org.remotestick;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View;
import android.widget.LinearLayout;
public class ColumnLayout extends LinearLayout
public ColumnLayout(Context context, AttributeSet attrs)
super(context, attrs);
public ColumnLayout(Context context)
super(context);
@Override
protected ContextMenuInfo getContextMenuInfo()
int itemTypeId = getChildAt(0).getId();
int positionTypeId = getId();
View currentView = this;
ViewPager viewPager = null;
while(currentView.getParent() != null)
currentView = (View) currentView.getParent();
if(currentView.getId() == R.id.pager)
viewPager = (ViewPager) currentView;
break;
else if (currentView.getId() == R.id.rootLayout)
break;
if(viewPager == null)
return null;
WorkspaceAdapter adapter = (WorkspaceAdapter) viewPager.getAdapter();
Pair<Integer, Integer> itemIdAndListPosition = adapter.getItemIdFromWorkspace(viewPager.getCurrentItem(), this, itemTypeId, (positionTypeId == R.id.leftColumn));
if(itemIdAndListPosition == null)
return null;
else
return new MatrixAdaptableContextMenuInfo(itemTypeId, itemIdAndListPosition.first, itemIdAndListPosition.second);
public static class MatrixAdaptableContextMenuInfo implements ContextMenuInfo
public final int itemTypeId;
public final Integer itemId;
public final Integer positionInList;
public MatrixAdaptableContextMenuInfo(int itemTypeId, Integer itemId, Integer positionInList)
this.itemTypeId = itemTypeId;
this.itemId = itemId;
this.positionInList = positionInList;
这是Fragment
的(sn-p):
public class EntityTableFragment extends Fragment implements TelldusEntityChangeListener
protected static final String ARG_TITLE = "title";
protected MatrixAdapter mAdapter;
protected ProgressViewer mProgressViewer;
protected MatrixFilter mFilter;
protected Handler mHandler = new Handler();
protected RemoteStickData db;
public boolean onAttach = false;
public boolean onCreateView = false;
private ListView listView;
public static EntityTableFragment newInstance(String title)
EntityTableFragment f = new EntityTableFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
f.setArguments(args);
return f;
@Override
public void onAttach(SupportActivity activity)
super.onAttach(activity);
onAttach = true;
try
mProgressViewer = (ProgressViewer) activity;
mAdapter = new MatrixAdapter(getActivity(), mProgressViewer, new ArrayList<List<MatrixEntity>>(), null);
TelldusLiveService.addListener(this);
catch (ClassCastException e)
throw new ClassCastException(activity.toString() + " must implement ProgressViewer");
db = new RemoteStickData(getActivity());
@Override
public void onDetach()
super.onDetach();
TelldusLiveService.removeListener(this);
@Override
public void onActivityCreated(Bundle savedInstanceState)
super.onActivityCreated(savedInstanceState);
listView.setAdapter(mAdapter);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.list, null);
listView = (ListView) view.findViewById(R.id.list);
return view;
@Override
public String toString()
return getArguments().getString(ARG_TITLE);
public Pair<Integer, Integer> getIdAndPositionForView(View v, boolean isLeft)
if(listView == null)
throw new IllegalStateException("Listview not yet created");
int positionForView = listView.getPositionForView(v);
if(isLeft)
return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(0).getId(), positionForView);
else
return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(1).getId(), positionForView);
当恢复应用程序时(如果 Activity 被销毁),ViewPager 及其 Fragments 及其 ListView 及其自定义布局都被绘制出来,这不是很奇怪。然而,如果我长按列表视图中的任何单元格,我会收到 IllegalStateException
说视图尚未创建?
编辑/
实际上,onCreateView
中的Log.d(Constants.TAG, "onCreateView!!!!");
输出表明,当我第一次启动应用程序时,方法被调用了两次(ViewPager 中的每个片段一个),但是当应用程序恢复时,它就再也没有被调用过!?这是一个错误还是我做错了什么?
【问题讨论】:
【参考方案1】:重要的部分似乎是FragmentPagerAdapter
(我没有包括在内)。调试显示重新创建活动时未调用getItem()
。片段是通过其他方式重新创建的。这意味着我对FragmentPagerAdapter
的实现错误地引用了FragmentManager
中的片段。
因此,当我需要查找片段时,我使用findFragmentByTag()
(在FragmentManager
)使用makeFragmentName()
来获取适当的标签名称。这是添加片段时FragmentPagerAdapter
使用的方法。不确定这是否是一种安全的方法。
【讨论】:
【参考方案2】:使用getChildFragmentManager()
代替getFragmentManager()
示例:
new ViewPagerAdapter(getChildFragmentManager());
而不是
new ViewPagerAdapter(((HomeActivity) context).getSupportFragmentManager())
【讨论】:
【参考方案3】:更好地使用 FragmentStatePagerAdapter,这样片段就会相应地重新创建。
【讨论】:
以上是关于在 ViewPager 中未使用 Fragment 调用 onCreateView的主要内容,如果未能解决你的问题,请参考以下文章
在Viewpager中的一个Fragment中添加一个ViewPager
Android ViewPager Fragment使用懒加载提升性能
Android ViewPager + Fragment 懒加载数据 可操作控件版