Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/185.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当内存不足时,Android不会停止堆栈中的活动_Android_Android Activity_Out Of Memory - Fatal编程技术网

当内存不足时,Android不会停止堆栈中的活动

当内存不足时,Android不会停止堆栈中的活动,android,android-activity,out-of-memory,Android,Android Activity,Out Of Memory,我们一直在开发一个应用程序,它有一个下拉式仪表板,允许用户在整个应用程序中导航。导航不是很标准,因为几乎每个活动都可以访问此菜单。 使用菜单打开活动播放一段时间后,堆栈开始不断增长 所有这些活动都包含包含多个图像视图的列表视图,每个视图大约占用3mb。如果用户玩得足够多,并在堆栈上创建超过25个活动,则会发生以下情况: 抛出内存不足错误(堆增加,直到不再有堆) 由于异常而显示对话框(很遗憾,%activity%已停止) 抛出OutOfMemorr的活动已完成 堆栈中的所有活动都已完成,但保留了历

我们一直在开发一个应用程序,它有一个下拉式仪表板,允许用户在整个应用程序中导航。导航不是很标准,因为几乎每个活动都可以访问此菜单。 使用菜单打开活动播放一段时间后,堆栈开始不断增长

所有这些活动都包含包含多个图像视图的列表视图,每个视图大约占用3mb。如果用户玩得足够多,并在堆栈上创建超过25个活动,则会发生以下情况:

  • 抛出内存不足错误(堆增加,直到不再有堆)
  • 由于异常而显示对话框(很遗憾,%activity%已停止)
  • 抛出OutOfMemorr的活动已完成
  • 堆栈中的所有活动都已完成,但保留了历史记录,因此可以进行备份,并由操作系统自动调用重新创建每个活动
  • 我希望系统在抛出OutOfMemoryError之前自动杀死堆栈中最早的活动

    为了确保操作系统不会扼杀旧的活动,我创建了一个测试应用程序,每次分配1mb。猜猜看:行为是相同的,并且抛出OutOfMemorRor:

    问题是:我们如何告诉Android操作系统,如果需要,它可以释放活动及其资源,这样我们就不会得到“不幸的是,您的活动已经停止”对话框

    概念证明

    当您开始新活动时调用
    finish()
    将取消分配您要离开的活动。这将阻止您使用“后退”按钮访问它,但它会降低内存

    我希望系统在抛出OutOfMemoryError之前自动终止堆栈中最早的活动

    Android并没有做到这一点。Android终止进程以释放系统内存供其他进程使用。它不会以类似的方式参与应用程序内部内存的使用

    我们如何告诉Android操作系统,如果需要,它可以释放活动及其资源,这样我们就不会出现“不幸的是,您的活动已经停止”对话框

    你不能

    相反,您需要将应用程序设计为使用更少的活动,或者每个活动使用更少的资源。例如,您可以通过“回收”现有活动实例,或者(正如Tornquist先生指出的那样),您可以自己手动
    finish()
    活动

    使用菜单打开活动播放一段时间后,堆栈开始不断增长


    您可能应该在这些菜单项上使用
    FLAG\u ACTIVITY\u REORDER\u TO\u FRONT
    ,这样您就可以在任务中推进现有的活动,而不是每次都创建新的活动。

    根据android开发者指南,我也有这样的印象,即系统将杀死旧的活动以释放内存:

    “当系统停止您的一项活动时(例如,当新活动开始或任务移到后台时),如果需要恢复系统内存,系统可能会完全销毁该活动。发生这种情况时,有关活动状态的信息将丢失。如果发生这种情况,系统仍然知道该活动在后堆栈中有一个位置,但当该活动到达堆栈顶部时,系统必须重新创建它(而不是继续)。为了避免丢失用户的工作,您应该通过在活动中实现onSaveInstanceState()回调方法来主动保留它。”

    见链接:

    使用意向标志\u活动\u重新排序\u至\u前端

     Intent i = new Intent(ActivityD.this, ActivityA.class);
      i.setFlags(FLAG_ACTIVITY_REORDER_TO_FRONT);
     startActivity(i);
    
    这将简单地将ActivityA带到堆栈的前面,并将B和C保留在我认为您需要的位置。然后,如果您想将其从堆栈中删除,显然可以调用D上的finish()。

    是正确的,此外,您可以尝试此策略来释放堆栈底部活动的内存:

    • 删除所有片段和/或
      setContentView(null)
    • onResume
      :调用
      活动#recreate()
      ,或者只需创建新的片段实例并将其添加回视图层次结构
    重要的一点是,不要依赖这些事件
    onLowMemory
    ontrimmory
    。因为只有在整个系统内存不足时才会调用这些事件,所以在此之前,应用程序可能会内存不足。如果进程占用了太多内存,您必须跟踪进程的内存使用情况,并采取适当的措施:

    val maxMemory = Runtime.getRuntime().maxMemory()
    val freeMemory = Runtime.getRuntime().freeMemory()
    val totalMemory = Runtime.getRuntime().totalMemory()
    val remainMemoryPercent = (freeMemory + maxMemory - totalMemory) * 100f / maxMemory
    
    // check remainMemoryPercent and take action
    

    谢谢,您的解决方案应该可以工作,但它也会从堆栈中删除已销毁的活动。我将遵循Commonware的建议,因为历史记录中至少保存了一个此类活动。谢谢!现在我们将使用建议的标志\u activity\u REORDER\u TO\u FRONT并实现onNewIntent回调,以确保活动得到更新有了新的意图。@commonware,doc确实说可以从堆栈中删除特定的活动。“暂停的活动完全处于活动状态(…),但在内存极低的情况下可以被系统删除。”和“(停止的活动)仍然保留所有的状态和成员信息,但是,它不再对用户可见,因此它的窗口被隐藏,并且当其他地方需要内存时,它通常会被系统杀死。”(链接)。这正是“不保持活动”的方式工具也能工作…@Alesqui:Android只会在终止整个过程时才这样做。但正如几个月前公认的答案所指出的,情况并非如此。
    val maxMemory = Runtime.getRuntime().maxMemory()
    val freeMemory = Runtime.getRuntime().freeMemory()
    val totalMemory = Runtime.getRuntime().totalMemory()
    val remainMemoryPercent = (freeMemory + maxMemory - totalMemory) * 100f / maxMemory
    
    // check remainMemoryPercent and take action