我已就此问题做了大量阅读,但我仍然对如何解决这个问题感到茫然。基本上,我有一个视图寻呼机,然后有一个寻呼机适配器类,并将使用
实例化我的片段 public override Android.Support.V4.App.Fragment GetItem(int position)
{
switch (position)
{
case 0:
return new Batches();
case 1:
return new Track();
case 2:
return new Post();
case 3:
return new Upload();
case 4:
return new Admin();
default:
return new Track();
}
}
据我所知,这个命名有误导性(基于我读过的另一篇SO帖子),因为这个方法实际上是为类创建实例,或者如果已经创建的话,则返回它(即当你刷页面时。
也就是说,当您刷卡时,我需要一些自定义生命周期事件来提升我的碎片。根据我在SO上做的其他阅读,确定创建自定义界面是最好的方法。所以,这就是我所做的:
接口
interface ICustomFragmentLifecycleForPager
{
void onPausePagerFragment();
void onResumePagerFragment(int prevPage);
}
基于视图寻呼机页面更改事件的活动调用
private void ViewPager_PageSelected(object sender, ViewPager.PageSelectedEventArgs e)
{
int position = (int)e.Position;
ICustomFragmentLifecycleForPager fragmentToResume = (ICustomFragmentLifecycleForPager)adapter.InstantiateItem(viewPager, position);
fragmentToResume.onResumePagerFragment(previousActiveFragment);
ICustomFragmentLifecycleForPager fragmentToPause = (ICustomFragmentLifecycleForPager)adapter.InstantiateItem(viewPager, previousActiveFragment);
fragmentToPause.onPausePagerFragment();
previousActiveFragment = position;
}
最后,一个片段
的实现示例 public void onPausePagerFragment()
{
//deInitScanner();
}
现在,这就是问题所在。虽然我的寻呼机适配器类上面的GetItem调用应该只创建第一个实例,否则返回实例,我发现我的接口将调用GetItem并且它会创建一个类的第二个(不需要的)实例。
当我的应用程序启动时,在onResume生命周期中,我有一个方法调用,它确定默认情况下在启动时显示哪个页面。然后该逻辑调用另一种方法来执行页面更改。当它执行页面更改时,将为我的自定义生命周期引发ViewPager_PageSelected事件。因为那些使用InstantiateItem(也许这就是问题),它将实例化该类的新实例。我确保在GetItem运行之后我不设置页面并为我的所有类创建实例,但是在稍后调用它时它仍会创建一个新的。
如果我在应用程序中遇到一个断点,我会看到这个,我在SupportFragmentManager中有一个实例,当我检查它时,我看到了我的片段的两个实例。
我怀疑问题是: 1.我需要在我的界面上使用与InstantiateItem不同的东西来强制它获取已经存在的类的实例吗? 2. GetItem调用看到InstantiateItem是从视图分页器以外的其他东西调用的,因此具有不同的标记,因此,GetItem认为它没有创建该类的实例并创建另一个实例?
无论哪种方式,我都不确定如何解决这个用例。
请帮忙!
编辑 - 我已经尝试过这个解决方案来存储类,如果它已经实例化并返回,而不是每次都创建新的。基本上在寻呼机适配器类中,全局到GetItem,我为每个类做了类似的事情:
Batches batches;
Track track;
然后,在GetItem方法中,我稍微修改了case语句:
switch (position)
{
case 0:
if (batches == null)
{
batches = new Batches();
}
return batches;
case 1:
if (track == null)
{
track = new Track();
}
return track;
我切断了它,但是我为所有的情况做了。但是,我现在得到了这个例外。
Java.Lang.IllegalStateException:已添加片段:跟踪{42350aa8#1 id = 0x7f070097 android:switcher:2131165335:1}
谢谢!
答案 0 :(得分:0)
此方法实际上为类创建实例,如果已创建
则返回它
如果你告诉它,这个方法只会满足这个要求。目前,每次调用此方法时,您都在创建所请求类的新实例。
要解决此问题,您需要在第一次创建实例时存储实例。然后,如果已经创建了相同的实例,则可以返回该实例。这样做需要更多代码。
答案 1 :(得分:0)
经过一些线索,更多的阅读和一些测试,我相信我找到了答案。但是,如果有人反对或知道更好的方法,那么请纠正我。
当与寻呼机适配器一起使用时,我了解到,如果仅使用基本实现,InstantiateItem将每次创建一个类/片段的实例。开发人员可以覆盖它并在创建后存储创建的片段,然后使用GetItem返回它。我也知道InstantiateItem会调用GetItem。
我相信发生的事情是,我的GetItem实现只是创建片段的一个实例。在创建它们之后,我没有明确地存储它们的实例。也就是说,这并不是完全必要的,因为如果SupportFragmentManager已经有了该类的实例,则不需要调用GetItem,这就是每次都不创建多个实例的方式。
也就是说,我实现的自定义生命周期接口(参见上面的OP)是调用InstantiateItem。因此,当调用和使用它时,它将创建我的片段的另一个实例,因为之前已创建的实例具有不同的标记名称。所以,我会有两个(但只有两个)。一个由寻呼机适配器创建的,一个是由我的界面调用的InstantiateItem创建的。
所以,修复是(似乎有效)是:
更改GetItem,以便在创建片段后存储对片段的引用,并返回存储的实例或如果为null则创建new。喜欢这个
Batches batches;
if (batches == null) {
batches = new Batches();
}
return batches;
确保寻呼机适配器类已完成,并且GetItem已在接口可以调用之前为类创建了一个实例(并存储它们)。这可确保创建和存储的实例是寻呼机适配器的实例,并具有正确的标记。
最后,最大的变化。我正在使用的接口的实现是调用InstantiateItem(我从SO得到这个)来获取对类的引用。如上所述,这是创建一个新实例。但是,如果我将其更改为GetItem,它将简单地获取并返回由寻呼机适配器创建和存储的片段的实例。所以,它应该是这样的:
ICustomFragmentLifecycleForPager fragmentToResume = (ICustomFragmentLifecycleForPager)adapter.GetItem(position); //InstantiateItem(viewPager, position);
fragmentToResume.onResumePagerFragment(previousActiveFragment);
希望这有帮助!