为啥调用 Process.killProcess(Process.myPid()) 是个坏主意?
Posted
技术标签:
【中文标题】为啥调用 Process.killProcess(Process.myPid()) 是个坏主意?【英文标题】:Why is calling Process.killProcess(Process.myPid()) a bad idea?为什么调用 Process.killProcess(Process.myPid()) 是个坏主意? 【发布时间】:2012-06-14 14:31:18 【问题描述】:我读过一些帖子说使用这种方法“不好”,不应该使用,它不是“关闭”应用程序的正确方法,它不是 android 的工作方式......
我理解并接受 Android 操作系统比我更清楚何时终止进程的正确时间这一事实,但我还没有听到关于为什么使用 killProcess()
方法是错误的很好的解释。毕竟 - 它是 Android API 的一部分。
我所知道的是,在其他线程正在执行潜在的重要工作(文件操作、写入数据库、HTTP 请求、运行服务..)时调用此方法会导致线程被终止,这显然不好。另外,我知道“重新打开”应用程序会更快,因为系统从上次使用应用程序时仍“保持”在内存状态,而killProcess()
阻止了这种情况,我可以从中受益。
除了这个原因,假设我没有这样的操作,并且我不在乎我的应用程序是否每次打开时都会从头开始,还有其他原因我不应该使用killProcess()
方法?
我知道关闭Activity
的finish()
方法,所以请不要在你的回答中包含它。
finish()
仅适用于Activity
,并非适用于所有应用程序,我想我确切知道为什么以及何时使用它。
还有一件事 - 我正在使用 Unity3D 框架开发游戏并将项目导出到 Android。当我对生成的apk进行反编译时,我很惊讶地发现,从unity创建的java源代码——实现Unity的——Application.quit()
方法,带有Process.killProcess(Process.myPid())
。
Application.quit()
应该是根据 Unity3D 文档关闭游戏的正确方法(真的吗?也许我错了,错过了什么),那么 Unity 的框架开发人员为什么要在原生 Android 中实现这一点?
【问题讨论】:
你所说的“不好”是什么意思——关于线程操作? 【参考方案1】:<rant>
在一个完美的世界中,拥有完美的代码和库,您不需要调用Process.killProcess(Process.myPid())
,操作系统会在适当的时候正确地终止您的应用程序。中东也将和平,猪会飞,halting problem会解决。
因为所有这些事情都还没有发生,所以有时您需要执行这样的“禁止”代码。
我最近为我制作的一款 Android 游戏,免费版本使用了一个广告库,它可以让应用程序保持活动状态并且还会泄漏内存。付费版本没有这个问题,因为没有链接广告库。我的解决方案是在执行此类代码的主菜单上添加一个退出按钮。我希望大多数人在完成后会点击这个按钮,我不必担心它会占用内存。我刚刚执行了finish()
的付费版本就完成了。 (这是在谷歌应用内购买可用之前,所以我必须制作一个付费和免费版本,他们现在可能已经解决了这个问题,我可以更新所说的游戏,但它确实做得不太好,我怀疑花在它上面的任何时间都是值得的)
这有点像在小学/初中,他们告诉你不能取负数的平方根。然后在更高级别的代数课上,他们说......好吧,你可以取负数的平方根,但你会得到奇怪的结果,但它是一致的并且解决了问题。
换句话说,除非您知道自己在做什么,否则不要执行“禁止”代码。
</rant>
【讨论】:
喜欢你的回答,但这有点像 liorry 已经以更哲学的方式说过的话。我在“应用内购买”的故事中有点迷失了你,但得到了你最后的主要内容观点。我给了你我的赞成票,因为你提出了一个有趣的观点.. 天哪,我还以为是错字,抱歉老兄,现在这很讽刺。【参考方案2】:谁说调用 Process.killProcess(Process.myPid()) 是个坏主意?
是的,让操作系统管理自己的内存是您和使用您的应用程序的用户的最佳做法(再次打开更快,强制关闭的机会更少,等等...)。
但是,假设您确定您没有中断线程或其他后台操作,并且您在 onDestroy()
中使用此调用 - 我认为您没有理由不使用它。尤其是当它是 API 调用而不是解决方法时,而且 Google 没有在 API 文档中提到最好不要使用它。
【讨论】:
“谁说调用 Process.killProcess(Process.myPid()) 是个坏主意?” -- Android 核心开发团队,尤其是 Dianne Hackborn 和 Romain Guy 等工程师。 @CommonsWare 它不好的原因是什么? 它阻止框架和核心系统进程相对于应用程序的进程(例如,任务历史记录)进行自己的清理。 这就像说“死于癌症”和“死于中弹 73 次”是等价的。是的,最终结果是一样的。不,你到达那里的方式有很大不同。值得注意的是,您提到的其他事情还有许多其他部分(例如,强制停止设置一些标志以防止广播接收器在手动启动活动之前运行)。现在,我不是固件专家。我只是报告我从与工程师的对话中了解到的内容以及这些工程师公开发布的内容。 @CommonsWare:如果我希望我自己的应用程序“完全死掉”并释放与之相关的所有内存:除非它会对其他应用程序或系统本身造成问题 - 我不在乎是癌症、霰弹枪或阿诺德施瓦辛格在做这项工作。所以请告诉我你是否知道它会导致这样的问题。如果不是 - 我将不得不同意 liorry、Russ 和 Tom 的观点。【参考方案3】:嗯,Unit3d 很可能使用本机代码,并且他们将终止进程作为保险——他们不想泄漏内存。您可以争论这是否是一个好主意,但他们使用它的事实并不意味着您也应该这样做。
也许在某些极端情况下您会想要使用killProcess()
,但通常操作系统会根据当前负载和使用情况为您执行此操作。不确定您正在寻找什么样的答案——您知道使用 killProcess()
可能会破坏事情,除非您能证明其使用是合理的,否则不要使用它。
【讨论】:
正如您所说,这确实不是我正在寻找的答案,但它肯定值得一票。你提出了一些有趣的观点。 我认为他们更有可能无法正确清理他们的原生资源并使用 killProcess() 作为创可贴修复。 ~“killProcess() 可能会破坏”。什么样的东西?【参考方案4】:在以下两种情况下 killProcess 会咬你而不按预期工作:
粘性服务 - 即使您终止了进程,它们也会自动重新启动
Timer - 如果您安排线程在 Timer 上运行,它们将在终止进程后继续执行
因此,如您所见,在某些情况下 killProcess 不是清理正在运行的应用程序的审慎解决方案。
【讨论】:
看起来甚至 NOT_STICKY 服务都重新启动了——此外,服务接收到 onCreate() 回调但没有接收到 onStartCommand() 回调,这完全破坏了生命周期。我对机制不是 100% 确定,但我在实际代码中遇到过这个问题。【参考方案5】:这是个坏主意。一方面,您的活动不值得使用检测,因为这些框架在所有生命周期方法上注册,并且只有在干净执行后它们才会报告测试成功状态。如果您从测试应用程序下方终止该进程,它将报告失败,并且不清楚这是否正在发生。
【讨论】:
【参考方案6】:在我看来,一些Android开发人员不推荐kill进程的原因是,如果你只是简单地杀死进程,很难确保所有的服务、活动都安全、正确地退出。对于一个APP开发者来说,他们的APP可能会与其他APP共享数据,一些Activity可能会导出给其他APP。如果您终止该进程,其他应用程序可能会出错。 而且,在大多数情况下,您实际上不需要“杀死”应用程序,只需完成您正在做的和您不想让用户看到的工作,将其他工作留给Android系统。他们比我们更了解。 好吧,如果你清楚你想做什么,不要关心打开速度等等,比如你想在用户点击某个按钮时退出游戏,你的游戏当然不会导出到其他应用程序,也不会在外面分享数据您的游戏,可以这样做,只需小心确保没有其他服务或线程需要运行。在这种情况下,我建议在终止进程之前完成所有活动,以确保活动正确保存状态,我将调用类似:
activity.finishAffinity();
Process.killProcess(Process.myPid());
在当前活动中。 这只是我的看法,欢迎指正。
【讨论】:
以上是关于为啥调用 Process.killProcess(Process.myPid()) 是个坏主意?的主要内容,如果未能解决你的问题,请参考以下文章