每当执行广播时,我都希望对前景活动显示警报。
每当执行广播时,我都希望对前景活动显示警报。
Answers:
知道ActivityManager可以管理Activity,因此我们可以从ActivityManager获取信息。我们通过以下方式获得当前正在运行的前景
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
UPDATE 2018/10/03
getRunningTasks()已弃用。请参阅下面的解决方案。
从API级别21开始不推荐使用此方法。从Build.VERSION_CODES.LOLLIPOP开始,此方法不再对第三方应用程序可用:以文档为中心的最新消息的引入意味着它可以将个人信息泄露给调用者。为了向后兼容,它仍将返回其数据的一小部分:至少调用者自己的任务,以及可能已知的一些其他不敏感的任务,例如home。
(注意: API 14中添加了一个官方API:请参阅此答案 https://stackoverflow.com/a/29786451/119733)
不要使用以前的(waqas716)答案。
由于对活动的静态引用,您将遇到内存泄漏问题。有关更多详细信息,请参见以下链接http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
为避免这种情况,您应该管理活动引用。在清单文件中添加应用程序的名称:
<application
android:name=".MyApp"
....
</application>
您的应用程序类:
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
创建一个新的活动:
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
因此,现在不必扩展活动的Activity类,而只需扩展MyBaseActivity。现在,您可以从应用程序或活动上下文中获取当前活动,如下所示:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
WeakReferences
在Android中使用GC来收集它们的速度比您想象的要快。
WeakReference
不建议将Cache 用于缓存,这不是缓存,也就是说,mCurrentActivity
仅当它处于活动状态时,才会对其进行引用,因此,WeakReference
永远不会在Activity
处于顶部时收集它们。但是@NachoColoma的建议是错误的,因为WeakReference
如果未清除该变量,它仍可能引用未恢复的活动(不在活动状态/不在顶部)!
Application .ActivityLifecycleCallbacks
,它将更加集中,并且您不必在所有活动中添加任何管理代码。另请参阅developer.android.com/reference/android/app/...
我在@gezdy的答案上方展开。
在每个活动中,我们无需Application
使用手动编码“注册”自己,而可以使用自第14级以来的以下API,以帮助我们以较少的手动编码实现类似的目的。
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
在中Application.ActivityLifecycleCallbacks
,您可以获取与此Activity
“连接”或“分离”的对象Application
。
但是,此技术仅在API级别14起可用。
implements Application.ActivityLifecycleCallbacks
,然后添加实现它的方法。然后在该类的构造函数中(或onCreate或init或在实例变为活动/就绪状态时运行的其他方法)中,将其getApplication().registerActivityLifecycleCallbacks(this);
作为最后一行。
更新2:为此添加了一个官方api,请改用ActivityLifecycleCallbacks。
更新:
正如@gezdy所指出的,我对此表示感谢。也将引用设置为null当前活动的,而不是仅在每个onResume上进行更新,而是在每个Activity的onDestroy上将其设置为null以避免内存泄漏问题。
前一阵子我需要相同的功能,这是我实现这一目标的方法。在您的每项活动中都应覆盖这些生命周期方法。
@Override
protected void onResume() {
super.onResume();
appConstantsObj.setCurrentActivity(this);
}
@Override
protected void onPause() {
clearReferences();
super.onPause();
}
@Override
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = appConstantsObj.getCurrentActivity();
if (this.equals(currActivity))
appConstantsObj.setCurrentActivity(null);
}
现在,在您的广播课程中,您可以访问当前活动以在其上显示警报。
Application
仅创建一次,并且永远不会像静态变量一样完全进行垃圾回收。
clearReferences()
来(this.equals(currActivity))
。
@lockwobr感谢您的更新
在api版本16中,这不能100%地起作用,如果您在github上阅读代码,则Kitkat中的函数“ currentActivityThread”已更改,因此我想说的是19ish版本,很难将api版本与github中的发行版进行匹配。
获得最新消息Activity
非常方便。有一个静态的不是很好吗getActivity
方法返回当前Activity而没有不必要的问题,吗?
该Activity
班是非常有用的。它提供对应用程序的UI线程,视图,资源等的访问。许多方法都需要一个Context
,但是如何获取指针呢?以下是一些方法:
ActivityThread
。此类可以访问所有Activity,更妙的是,它具有用于获取current的静态方法ActivityThread
。仅有一个小问题–活动列表具有程序包访问权限。使用反射很容易解决:
public static Activity getActivity() {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
if (activities == null)
return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
}
这种方法可以在应用程序中的任何位置使用,并且比所有提到的方法都方便得多。而且,看起来它并不像看上去那样不安全。它不会引入任何新的潜在泄漏或空指针。
上面的代码片段缺少异常处理,并且天真地假定第一个正在运行的Activity是我们要寻找的Activity。您可能需要添加一些其他检查。
Map
interface HashMap
或ArrayMap
。我已经编辑了@AZ_答案。
我在科特林做了以下活动
如下编辑应用程序类
class FTApplication: MultiDexApplication() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
}
init {
instance = this
}
val mFTActivityLifecycleCallbacks = FTActivityLifecycleCallbacks()
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(mFTActivityLifecycleCallbacks)
}
companion object {
private var instance: FTApplication? = null
fun currentActivity(): Activity? {
return instance!!.mFTActivityLifecycleCallbacks.currentActivity
}
}
}
创建ActivityLifecycleCallbacks类
class FTActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks {
var currentActivity: Activity? = null
override fun onActivityPaused(activity: Activity?) {
currentActivity = activity
}
override fun onActivityResumed(activity: Activity?) {
currentActivity = activity
}
override fun onActivityStarted(activity: Activity?) {
currentActivity = activity
}
override fun onActivityDestroyed(activity: Activity?) {
}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
}
override fun onActivityStopped(activity: Activity?) {
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
currentActivity = activity
}
}
您现在可以通过调用以下命令在任何类中使用它: FTApplication.currentActivity()
getCurrentActivity()也位于ReactContextBaseJavaModule中。
(由于最初提出了这个问题,因此许多Android应用也具有ReactNative组件-混合应用。)
ReactNative中的ReactContext类具有维护mCurrentActivity的整个逻辑集,该逻辑在getCurrentActivity()中返回。
注意:我希望getCurrentActivity()在Android Application类中实现。
我找不到能使我们的团队满意的解决方案,所以我们自己动手了。我们ActivityLifecycleCallbacks
用来跟踪当前活动,然后通过服务公开它。此处有更多详细信息:https : //stackoverflow.com/a/38650587/10793
为了向后兼容:
ComponentName cn;
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
cn = am.getAppTasks().get(0).getTaskInfo().topActivity;
} else {
//noinspection deprecation
cn = am.getRunningTasks(1).get(0).topActivity;
}
WeakReference
从Application
类中获取一个句柄-同时ComponentName
需要确定该类是否Activity
在运行任务列表的顶部。如果这不能完全回答问题,那么接受的答案也不会。
topActivity
仅可从Android Q
我个人按照“ Cheok Yan Cheng”的说法进行操作,但是我使用“ List”对所有活动进行“ Backstack”操作。
如果要检查哪个是当前活动,则只需要获取列表中的最后一个活动类。
创建一个扩展“应用程序”的应用程序,然后执行以下操作:
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks,
EndSyncReceiver.IEndSyncCallback {
private List<Class> mActivitiesBackStack;
private EndSyncReceiver mReceiver;
private Merlin mMerlin;
private boolean isMerlinBound;
private boolean isReceiverRegistered;
@Override
public void onCreate() {
super.onCreate();
[....]
RealmHelper.initInstance();
initMyMerlin();
bindMerlin();
initEndSyncReceiver();
mActivitiesBackStack = new ArrayList<>();
}
/* START Override ActivityLifecycleCallbacks Methods */
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
mActivitiesBackStack.add(activity.getClass());
}
@Override
public void onActivityStarted(Activity activity) {
if(!isMerlinBound){
bindMerlin();
}
if(!isReceiverRegistered){
registerEndSyncReceiver();
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if(!AppUtils.isAppOnForeground(this)){
if(isMerlinBound) {
unbindMerlin();
}
if(isReceiverRegistered){
unregisterReceiver(mReceiver);
}
if(RealmHelper.getInstance() != null){
RealmHelper.getInstance().close();
RealmHelper.getInstance().logRealmInstanceCount("AppInBackground");
RealmHelper.setMyInstance(null);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if(mActivitiesBackStack.contains(activity.getClass())){
mActivitiesBackStack.remove(activity.getClass());
}
}
/* END Override ActivityLifecycleCallbacks Methods */
/* START Override IEndSyncCallback Methods */
@Override
public void onEndSync(Intent intent) {
Constants.SyncType syncType = null;
if(intent.hasExtra(Constants.INTENT_DATA_SYNC_TYPE)){
syncType = (Constants.SyncType) intent.getSerializableExtra(Constants.INTENT_DATA_SYNC_TYPE);
}
if(syncType != null){
checkSyncType(syncType);
}
}
/* END IEndSyncCallback Methods */
private void checkSyncType(Constants.SyncType){
[...]
if( mActivitiesBackStack.contains(ActivityClass.class) ){
doOperation() }
}
}
就我而言,我使用“ Application.ActivityLifecycleCallbacks”来:
绑定/解除绑定Merlin实例(用于在应用程序丢失或获得连接时(例如,当您关闭移动数据或打开移动数据时)获得事件)。禁用“ OnConnectivityChanged”意图操作后,此功能很有用。有关MERLIN的更多信息,请参见:MERLIN INFO LINK
当应用程序关闭时,关闭我的最后一个Realm Instance;我将在所有其他活动的BaseActivity范围内对其进行初始化,该活动具有私有RealmHelper实例。有关REALM的更多信息,请参见:REALM INFO LINK 例如,我在“ RealmHelper”类中有一个静态“ RealmHelper”实例,该实例在我的应用程序“ onCreate”中实例化。我有一个同步服务,其中创建了新的“ RealmHelper”,因为Realm是“线程链接的”,并且Realm实例不能在其他线程中工作。因此,为了遵循Realm文档“您需要关闭所有打开的Realm实例以避免系统资源泄漏”,为完成此任务,我使用了“ Application.ActivityLifecycleCallbacks”,您可以看到。
最后,当我完成对应用程序的同步时,我将触发一个接收器,然后在同步结束时它将调用“ IEndSyncCallback”“ onEndSync”方法,在该方法中,我查看是否在ActivityBackStack列表中有特定的Activity类,因为我需要如果同步更新了视图中的数据,则更新视图中的数据,应用同步后,我可能需要执行其他操作。
就这样,希望对您有所帮助。再见 :)
waqas716的答案很好。我为需要较少代码和维护的特定案例创建了解决方法。
通过使用静态方法从我怀疑在前台的活动中获取视图,我找到了一种解决方法。您可以遍历所有活动并检查您是否愿意或从马丁的答案中获得活动名称
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
然后,我检查视图是否不为null并通过getContext()获取上下文。
View v = SuspectedActivity.get_view();
if(v != null)
{
// an example for using this context for something not
// permissible in global application context.
v.getContext().startActivity(new Intent("rubberduck.com.activities.SomeOtherActivity"));
}
getRunningTasks
:"Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, ..."
在developer.android.com/reference/android/app/...
我不喜欢其他答案。不打算将ActivityManager用于获取当前活动。依赖于onDestroy的超级分类也很脆弱,而不是最佳设计。
老实说,到目前为止,我想出的最好的办法就是在我的应用程序中维护一个枚举,该枚举在创建活动时设置。
另一个建议是,尽可能避免使用多个活动。这可以通过使用片段或在我的首选项自定义视图中完成。
一个相当简单的解决方案是创建一个单例管理器类,您可以在其中存储对一个或多个“活动”或整个应用程序中您想访问的任何内容的引用。
呼叫 UberManager.getInstance().setMainActivity( activity );
主活动的onCreate。
调用UberManager.getInstance().getMainActivity();
应用中的任意位置以进行检索。(我正在使用它来从非UI线程使用Toast。)
确保UberManager.getInstance().cleanup();
在销毁应用程序时添加呼叫。
import android.app.Activity;
public class UberManager
{
private static UberManager instance = new UberManager();
private Activity mainActivity = null;
private UberManager()
{
}
public static UberManager getInstance()
{
return instance;
}
public void setMainActivity( Activity mainActivity )
{
this.mainActivity = mainActivity;
}
public Activity getMainActivity()
{
return mainActivity;
}
public void cleanup()
{
mainActivity = null;
}
}
我想晚3年了,但是无论如何我都会回答,以防有人像我那样找到它。
我通过简单地使用以下方法解决了这个问题:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
请注意,“ getIntent()。toString()”包括一堆其他文本,例如程序包名称和活动的所有意图过滤器。从技术上讲,我们正在检查当前意图,而不是活动,但结果是相同的。只需使用例如Log.d(“ test”,getIntent()。toString()); 如果您想查看所有文本。该解决方案有点笨拙,但是代码中的代码更加简洁,功能相同。