为什么调用 Process.killProcess(Process.myPid()) 是一个不好的想法?

33

我看到一些帖子说使用这种方法是“不好的”,不应该使用,这不是“关闭”应用程序的正确方法,也不是Android的工作方式……

我知道并接受Android操作系统比我更懂何时终止进程,但我还没有听到为什么使用 killProcess() 方法是错误的好解释。毕竟,它是Android API的一部分。

我所知道的是,在其他线程执行可能很重要的工作(对文件进行操作、写入数据库、HTTP请求、运行服务)时调用此方法会导致这些线程被终止,这显然是不好的。此外,我知道我可以从中获益,因为“重新打开”应用程序将更快,因为系统仍然保留了上次使用应用程序的状态,而 killProcess() 可以防止这种情况发生。

除此之外,假设我没有这样的操作,并且我不关心应用程序每次启动时是否从头开始,还有其他原因使我不能使用 killProcess() 方法吗?

我知道使用 finish() 方法可以关闭一个 Activity,所以请不要在你的回答中包含它。

finish() 仅适用于 Activity,而不是所有应用程序,我认为我很清楚何时使用它。

还有一件事 - 我正在使用Unity3D框架开发游戏,并将项目导出到Android。当我反编译生成的apk时,我非常惊讶地发现从unity创建的java源代码实现了Unity的 Application.quit() 方法,并使用了Process.killProcess(Process.myPid())

根据Unity3D文档,Application.quit() 应该是关闭游戏的正确方法(真的吗?也许我错过了什么),那么为什么Unity框架开发人员会在本地Android中实现这个呢?


你所说的“不好”是指线程操作方面的什么问题? - IgorGanapolsky
6个回答

16

<抱怨>

在一个完美的世界里,有完美的代码和库,你不应该需要调用Process.killProcess(Process.myPid()),操作系统会正确地杀死你的应用程序。此外,中东将会和平,猪会飞,停机问题也会被解决。

因为这些事情还没有发生,所以有时候你需要执行这样的“禁止”的代码。

最近我制作了一个Android游戏,免费版使用的广告库会让应用程序保持活动状态并泄漏内存。付费版没有这个问题,因为没有链接广告库。我的解决方案是在主菜单上添加一个退出按钮来执行这样的代码。我希望大多数人完成后都会点击这个按钮,这样我就不必担心它会占用内存。对于付费版,我只需执行finish()就可以了。(当时谷歌尚未推出应用内购买,所以我不得不制作付费和免费版本,而且他们现在可能已经解决了这个问题,但那个游戏表现不佳,我认为花时间更新它是不值得的)

在小学或初中时,老师告诉你不能对负数求平方根。但在更高级别的代数课程中,他们会说...好吧,你可以对负数求平方根,但结果很奇怪,但是它是一致的并且解决了问题。
换句话说,除非你知道自己在做什么,否则不要执行“禁止”的代码。 </rant>

2
我喜欢你的回答,但它有点像以更哲学的方式表达了liorry已经说过的话。"应用内购买"的故事让我有些迷惑,但我理解了你的最终主要观点。我给了你我的赞,因为你提出了一些有趣的观点。 - Tal Kanel
1
哦,我以为那是打错了,非常抱歉,现在这就是讽刺。 - Jeremy Thompson
我希望我能够给予两个赞。前台服务也是如此。尽管你的回复已经快10年了,Admob仍然会导致内存泄漏。 - Atakan Yildirim

10

谁说调用Process.killProcess(Process.myPid()) 是一个不好的想法?

是的,让操作系统管理它自己的内存对你和使用你的应用程序的用户来说都是最佳实践(更快地重新打开,更少的强制关闭等等...)。

然而,假设你确定你没有中断线程或其他后台操作,并且你在onDestroy() 中使用此调用 - 我看不出为什么你不应该使用它。尤其是当它是一个API调用而不是一个变通方法时,而且谷歌也没有在API文档中提到不要使用它会更好。


15
“谁说调用 Process.killProcess(Process.myPid()) 是一个坏主意?”——核心 Android 开发团队,尤其是像 Dianne Hackborn 和 Romain Guy 这样的工程师。 - CommonsWare
5
@CommonsWare,它为什么不好? - Lior Iluz
3
它防止框架和核心系统进程相对于应用程序进程(例如任务历史记录)进行自己的清理。 - CommonsWare
5
这就好比说“癌症死亡”和“被枪击73次死亡”是相等的。是的,最终结果一样。但是,到达目标的方式是大不相同的。值得注意的是,你提到的其他事情有许多其他部分(例如,强制停止设置某些标志以防止广播接收器在手动启动活动之前运行)。现在,我不是固件专家。我只是根据与工程师的对话和那些工程师公开发布的内容报告我的所知。 - CommonsWare
7
如果我希望自己的应用程序“完全退出”并释放与其相关的所有内存:除非它会对其他应用程序或系统本身造成问题,否则我不在乎使用什么方法,无论是癌症、猎枪还是阿诺德·施瓦辛格。因此,请告诉我您是否知道它可能会引起这样的问题。如果没有,我将同意Liorry、Russ和Tom的看法。 - Tal Kanel
显示剩余6条评论

9

很可能Unit3d正在使用本机代码,并将该进程终止作为一种保险策略,以防泄漏内存。你可以争论这是否是一个好主意,但他们使用它并不意味着你也应该使用。

也许有一些极端情况下,您想使用killProcess(),但通常操作系统会根据当前负载和使用情况来代替您执行此操作。我不确定您在寻找什么样的答案 - 除非您能够证明其使用,否则不要使用killProcess(),因为它可能会破坏某些东西。


正如你所说,这并不是我正在寻找的答案,但它确实值得点赞。你提出了一些有趣的观点。 - Tal Kanel
我认为更有可能的是他们无法正确清理其本地资源,并使用killProcess()作为一种临时解决方案。 - safety
"killProcess()可能会破坏一些东西"。是哪些东西? - IgorGanapolsky

3
以下有两种情况下,killProcess 会失效并不能按照预期工作:
  1. 粘性服务 - 即使你杀死了进程,它们也会自动重新启动

  2. 定时器 - 如果你在定时器上安排线程运行,它们将在杀死进程后继续执行

因此,可以看到,在运行应用时,killProcess 并不是一种明智的清理方案。

1
看起来即使是NOT_STICKY服务也会重新启动 - 而且,Service接收到onCreate()回调但没有onStartCommand()回调,这完全破坏了生命周期。我不确定机制是否正确,但我在实际代码中遇到了这个问题。 - PVoLan

0

这是一个不好的想法。首先,您的活动将无法与仪器一起使用,因为这些框架在所有生命周期方法上注册,并且只有在干净执行后才会报告测试成功状态。如果您从测试应用程序下面杀死进程,它将报告失败,并且不清楚正在发生什么。


0
在我看来,一些Android开发人员不建议杀死进程的原因是,如果你仅仅简单地杀死进程,很难确保所有服务和活动都能安全、正确地退出。对于应用程序开发人员来说,他们的应用程序可能与其他应用程序共享数据,某些活动可能会导出到其他应用程序。如果你杀死了进程,其他应用程序可能会出现问题。 此外,在大多数情况下,实际上你并不需要“杀死”应用程序,只需完成你正在做的事情和你不想用户看到的事情,将其他工作留给Android系统处理。他们比我们更懂。 好吧,如果你清楚地知道自己想要做什么,不关心打开速度等等,比如当用户点击某个按钮时你想退出游戏,你的游戏当然不会导出到其他应用程序,也不会在你的游戏之外共享数据,这样做是可以的,只需仔细确保没有其他服务或线程需要运行。在这种情况下,我建议在杀死进程之前完成所有活动,以确保活动正确保存状态,我会调用类似以下的内容:
    activity.finishAffinity();
    Process.killProcess(Process.myPid());

在当前活动中。 这只是我的观点,欢迎纠正我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接