问题,我如何才能获得当前活动?已经在Stackoverflow和其他网站上被问了几十次,并且有很多提议的方法。但是,所有这些都有某种形式的缺点。
在这篇文章中,我假设在Android的API中没有为此提供解决方案,例如:Application.getTask().getRootActivity()
。
如果有以下情况会不会很好: - )?
所以,要明确的是,我没有要求的答案如何才能获得当前的活动?
相反,我要问的是没有提供这种能力的原因。假设每个正在运行的应用程序都有一个任务(假设任务没有被清空)并且每个这样的任务都有一个root活动,那么提供对该根Activity的访问似乎很容易。
在没有提供此类访问权限的情况下,如果需要这样的话,这意味着对我来说,我不了解Android体系结构的基本内容。
我错过了什么?为什么Android API不提供此信息?
对于背景,这里是一个概述已经提出的一些方法的部分。我发现以下两个链接特别有用(下面的每个方法都在一个或两个链接中提供)。
链接
途径
ActivityManager
ActivityManager方法仅提供Activity类的名称,而不是当前的Activity实例。例如,对于上下文实例c:
c.getSystemService().getActivityManager()
.getAppTasks().get(0).getTaskInfo()
.topActivity().getClassName()
反射
我最喜欢的是_AZ提出的反思,但这种方法很脆弱,因为它依赖于内部。我想从Android看到的是这种方法是通过开发人员可以安全依赖的标准API提供的。
静态挂钩
最常见的方法是使用静态挂钩来保存对当前正在运行的Activity的引用。钩子可以是按活动或按应用程序。通过保存/破坏钩子的值可以避免内存泄漏(例如,在onCreate()/ onDestroy(),onStart()/ onStop(),onPause()/ onResume())。但是,当涉及多个活动时(例如,由于生命周期重叠 - 见下文),可能会出现问题。
我实现了一个静态钩子方法,它执行以下操作(完全透明,我还没有实现#1 - 我目前正在使用per-Activity静态钩子,这是一个bug)。
理论上,这将使我能够始终了解任务的后备堆栈的完整状态 - 完整的活动集,包括根活动,以及它们的当前状态。然而,在实践中,有一个转折 - 当一个活动开始另一个活动时,它们的生命周期重叠。在此期间,在堆栈停止时偷看可能会产生意外的Activity实例。
来自:https://developer.android.com/guide/components/activities/activity-lifecycle.html#soafa,"协调活动":
这是活动A启动时发生的操作顺序 活动B:
- 活动A的onPause()方法执行。
- 活动B的onCreate(),onStart()和onResume()方法按顺序执行。 (活动B现在具有用户关注点。)
- 然后,如果活动A在屏幕上不再可见,则其onStop()方法将执行
醇>
当然,这也可以管理。最重要的是我们确实有一个可用于存储信息的全局上下文(应用程序),我们确实拥有有关活动生命周期转换的完整信息,因此我付出了足够的努力,我相信这种基于静态堆栈的方法可能会成为相当的子弹 - 证明。
但最终
但最后感觉我只是简单地重写代码,这些代码可能已经存在于内部,用于管理一个Activity堆栈,这就是为什么我要问(如果你已经忘记了):
为什么没有用于获取当前活动的Android API?
在本次更新中,我将总结一下我从这个主题和我自己的实验和研究中学到的东西。希望这个摘要对其他人有用。
我将根据https://developer.android.com/guide/components/activities/activity-lifecycle.html上的活动状态定义,为"活动可见性状态"使用以下定义。
-----------------------------------
Visibility State Definition
-----------------------------------
Not Visible Created+Stopped
Partially Visible Started+Paused
Fully Visible Resumed
-----------------------------------
"当前活动的定义"是黑暗的。当我使用它时,我指的是处于完全可见状态的单个活动。在任何给定的时刻,可能有也可能没有这样的活动。特别是,当活动A启动活动B时,会调用A的onPause(),然后调用onCreate(),onStart()和onResume(),然后是A onStop()。在A的onPause()和B的onResume()之间存在一段延伸,其中两者都不处于完全可见状态,因此没有当前活动(因为我定义它)。当然,在某些情况下,后台线程可能想要访问当前活动,并且根本不存在活动,更不用说当前活动了。
我也意识到我可能并不总是需要一个Current("完全可见")活动。在许多情况下,我可能只需要对现有活动的引用,无论它是否当前可见。此外,该引用可能只适用于任何Activity(对于需要将通用Activity引用传递给某些API方法的情况),或者它可能是特定的Activity子类实例(这样我就可以触发一些特定于该Activity的代码)子类)。
最后,需要了解主UI循环器何时调用Activity生命周期回调以及如何处理配置更改等事件。例如,如果我使用当前位于" Not Visible"中的Activity intance创建DialogFragment。它会不会被显示出来,如果是的话,什么时候?类似地,事实证明由配置更改引起的onDestroy()和onCreate()方法包含在UI的消息队列中的相同消息中(请参阅Android UI Thread Message Queue dispatch order),因此没有其他消息将在这两个回调之间处理(在配置更改期间)。理解这种处理水平似乎是至关重要的,但如果不完全遗漏,那么它的文档就非常缺乏。
以下是一系列可用于解决上述大多数情况的方法。
有时候你想要在一个Activity" session"中停止/启动一个后台线程,在那里我定义" session"包括可能由于配置更改而创建和销毁的一系列Activity实例。在我的特定情况下,我有一个蓝牙聊天活动和一个相关的后台线程来处理网络连接。我不希望每次用户旋转设备时都会破坏和创建连接,因此我只有在不存在连接时才需要创建它,并且只有在配置更改不是时才销毁它进行。这里的关键是理解当由于配置更改而调用onDestroy()时。这可以使用或不使用片段来完成。通常情况下,我更喜欢非片段方法,因为片段方法对我来说似乎不值得额外的复杂性。
方法1:没有碎片
在onCreate()中,如果尚未存在,则创建后台线程。在onDestroy()中,仅当isFinally()返回false时才销毁后台线程。
方法2:使用碎片
这很有效,因为如果使用setRetainInstance(true),FragmentManager将在配置更改中存储片段实例。有关此示例,请参阅http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html。示例适用于AsyncTasks,但也可以应用于管理后台线程(只需在片段的onCreate()中创建线程而不是AsyncTask,然后销毁片段中的线程onDestroy() )。
完全理解这些问题需要深入了解UI looper如何处理其消息队列 - 调用Activity回调时,其他消息如何与它们交错,何时发生显示更新等。例如,如果DialogFragment是使用不可见活动的实例创建,它是否会显示,如果是,何时? 也许有一天Android会为Tasks及其相关的backstack提供更深入的API,以及更详细地描述UI的消息处理和相关机制的文档。在此之前,更多的源代码和/或......经验分析" :-)。
谢谢,
百里
答案 0 :(得分:0)
我猜测的简短答案是,在给定的应用程序中,一次只能激活一个活动,并且该活动显然知道它是谁(它本身) - 所以任何活动都可以获得的唯一答案"当前活动的活动"永远只会是#34;你是,愚蠢"。
对于在不同活动类之间进行明确划分的简单应用程序,这样可以正常工作,因此在游戏商店中大部分应用程序占很大比例。当你通过封装和多态性获得真正的聪明时,它并没有那么热,因为我确定你已经发现了,但我不认为谷歌真正瞄准那些开发人员类型。
只要我0.02美元,我就不会认为你会得到一个"官员"回答这里。
答案 1 :(得分:0)
如果你想要知道的是哪个Activity最重要并接受用户交互,只需创建一个扩展Activity并覆盖onResume()的BaseActivity,并保存对&#34的引用;这个"在一个静态变量中。您的所有其他活动都应扩展BaseActivity。你已经完成了。