Android-内存压力崩溃,查看页面>片段>活动

Android-内存压力崩溃,查看页面>片段>活动,android,memory-management,android-fragments,android-viewpager,activity-finish,Android,Memory Management,Android Fragments,Android Viewpager,Activity Finish,我在我们的应用程序中使用v4支持库,我在应用程序中有一个基于步骤的流程,在正常情况下运行良好。然而,我们有一个要求,即所有的东西都需要工作,并且在内存压力的情况下不会崩溃。因此,我使用SetAlwaysFinish库来帮助实现这一点。它在确定需要检测和处理这类情况的领域方面非常有用,但我遇到了一个让我困惑的问题。请记住,这在正常情况下可以正常工作,但我使用setAlwaysFinish=ON进行显式测试 以下是我的设置:我有一个ProcessActivity类,它承载ViewPager的布局。V

我在我们的应用程序中使用v4支持库,我在应用程序中有一个基于步骤的流程,在正常情况下运行良好。然而,我们有一个要求,即所有的东西都需要工作,并且在内存压力的情况下不会崩溃。因此,我使用SetAlwaysFinish库来帮助实现这一点。它在确定需要检测和处理这类情况的领域方面非常有用,但我遇到了一个让我困惑的问题。请记住,这在正常情况下可以正常工作,但我使用setAlwaysFinish=ON进行显式测试

以下是我的设置:我有一个ProcessActivity类,它承载ViewPager的布局。ViewPager有一个适配器集,其中包含我的包含该过程的片段列表。这在onCreate方法中:

try {
    getSupportFragmentManager().putFragment(outState, Fragment1Step.class.getName(), fragment1);
} catch (Exception e) {
    // do nothing
}
try {
    getSupportFragmentManager().putFragment(outState, Fragment2Step.class.getName(), fragment2);
} catch (Exception e) {
    // do nothing
}
etc...
过程活动:

还有其他部分,但这是其设置的核心。在其中一个片段步骤中,我实际上需要从步骤流程中断,暂时推出到一个活动,以执行一些逻辑,然后返回到步骤流程。由于我需要能够在活动完成时处理活动中的“确定/取消”操作,因此我按如下方式执行此操作,并获得一个ForResult:

步骤4片段:

一旦推到这个视图上,有时会由于alwaysFinish调用ProcessActivity和Step4Fragment的onDestroy方法。有时,它似乎工作得很好,并回调到步骤片段过程中。但通常,它会调用ProcessActivity的onDestroy方法,然后在填充bundle saved实例状态的情况下重新调用onCreate方法。这将调用上面的步骤创建代码,并将应用程序置于一种令人生厌的状态,即用户正在执行的最后一个步骤正在显示,但在幕后,它实际上在第一个步骤上。此时,片段处于异常状态并断开连接,崩溃不可避免地发生。在这一点上,Step4Fragment似乎是完全脱节的,如果您尝试做任何事情,它将在某个地方崩溃,即使它似乎被正确地重新实例化了

有什么想法可以解决这个问题吗?我认为如果我能找到一种方法,甚至只是重置一些东西,这样当内存出现问题时,用户就可以返回到流程的第一步。然而,我所关心的当然是这次坠机事件

如果我需要提供更多细节,请告诉我。提前感谢您的帮助

更新1: 只是一个快速更新,我注意到片段被重新实例化和初始化,它正确地落入当前片段的onActivityResult方法中,并正确地执行它需要执行的操作。断开连接的地方似乎在基本ProcessActivity类中,遵循以下场景之一。ViewPager布局显示正确,但ViewPager之外的所有内容都不正确,即它指示它处于流程的第一步,而它应该指示它处于第四步,并且导航按钮显示在第一步而不是第四步

所以我猜我需要手动正确设置这些元素。在深入研究这一点的过程中,我可能遗漏了一些代码片段,这些代码是有人需要积极帮助的。如果我可以在调用整个onDestroy/onCreate之前访问ViewPager字段的状态,该字段包含获取当前显示片段的功能,可能是从savedInstanceState包中访问?这可能会解决我的问题。但是在调试时检查这个包,我几乎只看到片段本身,以及它们各自的状态。不过我会继续挖的

无论如何,请让我知道,如果有任何人对如何正确地在高水平上做这类事情有任何想法,当然

更新2 我看到,即使当前的片段看起来是正确启动的,并且视图显示正确,所有的东西都是分离的。我不能调用getResources或getActivity等的任何方法。实际上,我能够通过将步骤索引int保存到savedInstanceState包中,然后重新加载其周围的UI元素,使ProcessActivity“正常工作”。然而,我仍然有一个拦截器,当前片段与活动分离,即使它似乎被正确地重新实例化

更新3
当我遵循这篇文章的方向时,当我尝试执行第一个putFragment时,我会立即遇到一个异常。异常为:IllegalStateException:Fragment Step4Fragment当前不在FragmentManager中。我想这可能是因为我在任何时候都只在左侧保留一个片段,在右侧保留一个片段“活动”,即offScreenPageLimit

您确定您的片段没有被删除吗

Fragment的所有子类必须包含一个公共空构造函数。 框架通常会在需要时重新实例化片段类,特别是在状态恢复期间,并且需要能够找到此构造函数来实例化它。如果空构造函数不可用,则在某些情况下,在状态还原期间会发生运行时异常


事实证明,这一问题的解决方案与本文中介绍的解决方案类似:

我有一些事情需要改变。首先,我需要将片段移动到字段,而不是临时变量。其次,我需要避免每次在onCreate中实例化新片段。相反,它应该尝试从savedInstanceState中提取它们,如下所示:

fragment1 = (Fragment1Step) getSupportFragmentManager().getFragment(savedInstanceState, Fragment1Step.class.getName());
fragment2 = (Fragment2Step) getSupportFragmentManager().getFragment(savedInstanceState, Fragment2Step.class.getName());
etc...
然后在这之后,我对每一个都进行了后续检查;如果它们是空的,即新的,而不是来自已保存的实例,则它们将被实例化为新的:

if (fragment1 == null) {
    fragment1 = new Fragment1Step();
} 
if (fragment2 == null) {
    fragment2 = new Fragment2Step();
} 
当然,为了使其正常工作,还应在onSaveInstanceState方法中保存以下内容:

try {
    getSupportFragmentManager().putFragment(outState, Fragment1Step.class.getName(), fragment1);
} catch (Exception e) {
    // do nothing
}
try {
    getSupportFragmentManager().putFragment(outState, Fragment2Step.class.getName(), fragment2);
} catch (Exception e) {
    // do nothing
}
etc...
我之所以在try/catch块中使用这些函数,是因为我们的ViewPager只有offScreenPageLimit为1,所以如果它们当前不在正在显示的片段的“活动”堆栈中,其中一些函数将在putFragment调用时抛出异常


这不是非常漂亮,也许有更好的方法来处理这件事。。但是,现在这样做似乎很好。

是的,所有的片段都在被重新实例化,它们都有公共的空构造函数。我将日志放在每个日志中,每个日志都被调用,它们都在我的帖子中提到的createSteps方法中实例化,在设置它们的主流程类的onCreate中。。所以他们肯定会被重新叫来。奇怪的是,从日志中可以看出,一切都准备妥当并被调用,以便在视图停止时重新设置视图。但实际上,它没有正确显示,如果在显示后执行任何操作,都会导致崩溃。在执行更多日志记录后,我意识到它确实会首先调用空构造函数,这是应该使用的实际构造函数,带有非空的附加活动。但是,当在此之后调用ProcessActivity类的onCreate时,它会重新创建片段,这些片段看起来是不连贯的片段。我很好奇如何在完成后从ProcessActivity类访问由系统正确重新实例化的“真实”片段。我尝试过很多不同的事情,但运气不太好@svguerin3通过我个人资料中的网站与我联系。如果你愿意,我会尝试通过skype帮助你。谢谢你,詹姆斯!我确实忽略了这篇文章:,这表明从onCreate创建片段不是一个好主意。因此,我将尝试尝试这里提到的解决方案。如果我仍然没有运气,我一定会联系你。非常感谢您愿意这样做!我会让你知道情况的,没问题。我认为这是初始化问题,尽管我认为这是通过一个非空构造函数实现的。祝你好运
try {
    getSupportFragmentManager().putFragment(outState, Fragment1Step.class.getName(), fragment1);
} catch (Exception e) {
    // do nothing
}
try {
    getSupportFragmentManager().putFragment(outState, Fragment2Step.class.getName(), fragment2);
} catch (Exception e) {
    // do nothing
}
etc...