Bar*_*oyd 9 android android-intent android-service android-activity
问题是,我如何获得当前的活动?已经在Stackoverflow和其他网站上被问了几十次,并且有很多提议的方法.然而,它们都具有某种形式的缺点.
在这篇文章中,我假设Android的API中没有为此提供解决方案,例如:Application.getTask().getRootActivity().
如果有:-)那不是很好吗?
所以,要清楚,我不是要求答案我如何获得当前的活动?
相反,我问的是没有提供这种能力的原因.假设每个正在运行的应用程序都有一个任务(假设任务没有被清空)并且每个这样的任务都有一个root活动,那么提供对该根Activity的访问似乎很容易.
在没有提供这种访问的情况下,当它非常明确地需要时,这对我来说意味着Android架构有一些我不理解的基础.
我错过了什么?为什么Android API不提供此信息?
作为背景,这里是一个概述已经提出的一些方法的部分.我发现以下两个链接特别有用(下面的每个方法都在一个或两个链接中提供).
链接
途径
ActivityManager
ActivityManager方法仅提供Activity类的名称,而不是当前的Activity实例.例如,对于Context实例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
-----------------------------------
Run Code Online (Sandbox Code Playgroud)
"当前活动"的定义是模糊的.当我使用它时,我指的是处于完全可见状态的单个活动.在任何给定的时刻,可能有也可能没有这样的活动.特别是,当活动A启动活动B时,A的onPause()被调用,然后是B的onCreate(),onStart()和onResume(),然后是A的onStop().在A的onPause()和B的onResume()之间有一段延伸,其中两者都不处于完全可见状态,因此没有当前活动(正如我定义的那样).当然,也存在后台线程可能想要访问当前活动的情况,并且可能存在或可能不存在活动,更不用说当前活动.
我也意识到我可能并不总是需要一个Current("完全可见")活动.在许多情况下,我可能只需要对现有活动的引用,无论它是否当前可见.此外,该引用可能只适用于任何Activity(对于我需要将一般的Activity引用传递给某些API方法的情况),或者它可能是一个特定的Activity子类实例(这样我就可以触发一些特定于该Activity的代码)子类).
最后,需要了解主UI循环器何时调用Activity生命周期回调以及如何处理配置更改等事件.例如,如果我使用当前处于"不可见"状态的Activity intance创建DialogFragment,它是否会显示,如果是,何时?类似地,事实证明由配置更改引起的onDestroy()和onCreate()方法包含在UI的消息队列中的相同消息中(请参阅Android UI线程消息队列调度顺序),因此不会有其他消息在这两个回调之间处理(在配置更改期间).理解这种级别的处理似乎是至关重要的,但是如果没有完全遗漏,那么它的文档就非常缺乏.
以下是可用于解决上述大多数情况的方法集合.
有时您可能希望仅在"活动"会话中停止/启动后台线程,其中我定义"会话"以包括可能由于配置更改而创建和销毁的一系列活动实例.在我的特定情况下,我有一个蓝牙聊天活动和一个相关的后台线程来处理网络连接.我不希望每次用户旋转设备时都会破坏和创建连接,因此我只需要在不存在连接时创建连接,并且只有在配置更改未进行时才销毁它.这里的关键是理解当由于配置更改而调用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的消息处理和相关机制的文档.在此之前,更多的"源代码和/或......实证分析":-).
谢谢,
巴里
alz*_*zee -1
我猜想的简短答案是,在给定的应用程序中一次只能有一个活动处于活动状态,并且该活动显然知道它是谁(它本身)——因此任何活动可以获得的唯一答案是“什么活动”当前处于活动状态”只能是“你是,傻瓜”。
对于不同活动类别之间有明确划分的简单应用程序来说,这种方法效果很好,因此这在 Play 商店中的大多数应用程序中占很大比例。当你真正熟练地使用封装和多态性时,它就不会那么热了,我相信你已经发现了,但我不认为 Google 真正针对的是这些类型的开发人员。
只是我的 0.02 美元,我认为您不会在这里得到“官方”答案。
| 归档时间: |
|
| 查看次数: |
1721 次 |
| 最近记录: |