【发布时间】:2014-02-19 10:32:18
【问题描述】:
我想要达到的目标:
带有 ViewPager 的 Activity 显示适配器中对象列表的片段 (FragmentStatePagerAdapter)。
最初,Activity 将 SQLite DB 中的 N 个(比如说 5 个)对象加载到适配器中。这些对象是随机选择的。
当用户到达列表末尾时,活动应从数据库中加载 M(假设 M 为 3)更多对象,将它们添加到适配器并调用 notifyDataSetChanged()。添加它们时,我会检查列表中是否已经存在新对象,如果存在,则会删除预先存在的对象,并将加载的对象添加到列表的尾部。
因此,我正在尝试实现类似 无限滚动 ViewPager (不是“循环” ViewPager,因为我希望不断获取新对象,而不是回到乞求列表)。
我有一些工作代码,并包含了我在下面遵循的模式的示例。但是,我不断收到此异常,不知道为什么:
IllegalStateException: Fragment MyObjectFragment{id...} is not currently in the FragmentManager
at android.app.FragmentManagerImpl.saveFragmentInstanceState(FragmentManager.java:553)
at android.support.v13.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:140)
at android.support.v4.ViewPager.populate(ViewPager.java:1002)
...
代码示例:
活动:
public class MyActivitty extends FragmentActivity {
public MyPagerAdapter adapter;
public ViewPager pager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_acyivity_layout);
pager = (ViewPager) findViewById(R.id.viewPager);
ArrayList<MyObject> myObjects = new ArrayList<MyObject>();
// loadInitialObjectsFromDB(int N) goes to SQLite DB and loads the N first objects to show on the ViewPager...
myObjects = loadInitialObjectsFromDB(5);
// Adapter will use the previously fetched objects
adapter = new MyPagerAdapter(this, getFragmentManager(), myObjects);
pager.setAdapter(adapter);
pager.setOffscreenPageLimit(2);
// (...)
}
// (...)
}
PagerAdapter:
public class MyPagerAdapter extends FragmentStatePagerAdapter implements
ViewPager.OnPageChangeListener {
private MyActivity context;
private ArrayList<MyObject> objectList;
private int currentPosition = 0;
// (...)
public MyPagerAdapter(MyActivity context, FragmentManager fragmentManager, ArrayList<MyObject> objects)
{
super(fragmentManager);
this.context = context;
this.objectList = objects;
}
@Override
public Fragment getItem(int position)
{
MyObject object = objectList.get(position);
return MyObjectFragment.newInstance(position, object);
}
@Override
public int getItemPosition(Object object){
MyObjectFragment frag = (MyObjectFragment) object;
MyObject object = frag.getMyObject();
for(int i = 0; i < objectList.size(); i++)
{
if(objectList.get(i).getId() == object.getId())
{
return i;
}
}
return PagerAdapter.POSITION_NONE;
}
@Override
public int getCount()
{
return objectList.size();
}
@Override
public void onPageSelected(int position)
{
currentPosition = position;
}
// (...)
}
@Override
public void onPageScrollStateChanged(int state)
{
switch(state)
{
case ViewPager.SCROLL_STATE_DRAGGING:
// (...)
break;
case ViewPager.SCROLL_STATE_IDLE:
// if we are reaching the "end" of the list (while scrolling to the right), load more objects
if(currentPosition <= position && position >= answerList.size()-1)
{
// Function in MyActivity that fetches N more objects.
// and adds them to this adapter's ArrayList<MyObject> objectList
// it checks for duplicates so that if the fetched object was already in the back of the list, it is shown again
context.getMoreObjects(3);
notifyDataSetChanged();
}
getMoreQuestions(currentPosition);
case ViewPager.SCROLL_STATE_SETTLING:
break;
}
}
我的片段:
public class MyObjectFragment extends Fragment {
// Object to represent
private MyObject object;
public static Fragment newInstance(MyActivity context,
int position, MyObject object) {
MyObjectFragment frag = new MyObjectFragment();
Bundle args = new Bundle();
args.putParcelable("Object", object);
frag.setArguments(args);
return frag;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.currentInflater = inflater;
final View rootView = inflater.inflate(
R.layout.fragment_my_object, container, false);
// get object from Bundle, set UI, events, etc...
}
// (...)
}
知道为什么我会收到这个Exception 吗?似乎FragmentStatePagerAdapter 正在尝试销毁不再存在的项目,但我不明白为什么。
编辑 1:
如果我评论我的@Override getItemPosition(Object object),我不会再收到异常。但是,我需要覆盖getItemPosition,因为在一个用例中,用户删除了当前显示的对象,导致它从适配器的数组中消失并强制getItemPosition返回POSITION_NONE,如果该项目不存在没有了。
编辑 2:
现在我知道只有当我从适配器的objectList 中删除项目时才会发生此异常。我有两种情况,从objectList 中删除MyObject 实例:
当
getMoreObjects()添加从数据库中获取一个已经在objectList中的对象时,我将其删除并重新添加到列表的头部。我这样做是为了避免在 objectList 中有具有相同 ID 的对象,因为getItemPosition()使用它们的 ID 来了解它们是否存在以及它们的位置。在返回之前,
getMoreObjects()从列表中删除前 N 个对象。我知道 FragmentStatePagerAdapter 已经通过只保留一些对象的内存片段来节省内存,但我仍然想避免我的objectList增长太多。目前,我已将这行注释掉,因为它并不重要。
【问题讨论】:
-
您说
These objects are chosen with some randomness.,但随后您使用objectList.get(position)获取objectList中具有预定义位置的项目以获取位置?我认为您对对象的位置搞砸了,这导致了异常。 -
@ShaktiThakran 是的,这些对象是从数据库中随机选择的。当用户接近列表末尾时,我从数据库中获得 N 个更多“随机”对象并将它们添加到 objectList 中。有可能我选择了一个已经在 objectList 中的项目,在这种情况下,我从任何地方删除它并再次将其添加到列表的尾部。通过这样做,我知道列表中没有“重复项”(具有相同的 object.Id),因为这可能会搞砸 getItemPosition()。
-
如果您在列表中找到它,为什么不选择不同的随机对象,而不是删除然后添加。我认为你可以不用移除部分。
-
因为在这种情况下,过去显示的项目(MyObject)再次显示是可以接受的。我可能只会将其作为最后一个资源。
-
是的,在这种情况下也是可能的,只需循环浏览可见视图。由于 setOffscreenPageLimit() 而被删除的那些仍然有机会重新出现。您唯一需要跳过的是已经在 offscreenPageLimits 内的那些。
标签: android android-fragments android-viewpager fragmentstatepageradapter