如何获取android中的当前前台活动上下文?

时间:2012-07-10 10:30:02

标签: android android-activity

每当我的广播被执行时,我想向前台活动显示警告。

15 个答案:

答案 0 :(得分:190)

注意: 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();

答案 1 :(得分:59)

我扩展了@ gezdy的答案。

在每个活动中,我们不需要使用手动编码将Application“注册”给自己,而是从14级开始使用以下API,以帮助我们以更少的手动编码实现类似目的。

public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

http://developer.android.com/reference/android/app/Application.html#registerActivityLifecycleCallbacks%28android.app.Application.ActivityLifecycleCallbacks%29

Application.ActivityLifecycleCallbacks中,您可以将[{1}}“附加”或“分离”到此Activity

但是,此技术仅适用于API级别14。

答案 2 :(得分:51)

更新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);
}

现在,在您的广播课程中,您可以访问当前活动以在其上显示提醒。

答案 3 :(得分:45)

@lockwobr 感谢您的更新

  

如果您阅读了,那么在api版本16中这不会100%有效   代码在github上的函数&#34; currentActivityThread&#34;改变了   Kitkat,所以我想说版本19ish,有点难以匹配api   版本发布在github中。

有权访问当前的Activity非常方便。使用静态getActivity方法返回当前活动并没有不必要的问题会不会很好?

Activity类非常有用。它可以访问应用程序的UI线程,视图,资源等等。许多方法需要Context,但如何获取指针?以下是一些方法:

  • 使用重写的生命周期方法跟踪应用程序的状态。 您必须将当前的Activity存储在静态变量中 需要访问所有活动的代码。
  • 使用Instrumentation跟踪应用程序的状态。宣布 清单中的仪表,实现它并使用它的方法 跟踪活动变化。将Activity指针传递给方法和 您的活动中使用的类。使用其中一个注入指针 代码注入库。 所有这些方法都是相当的 不方便; 幸运的是,有一种更容易获得的方法 当前活动。
  • 好像系统需要访问所有活动而没有 上面提到的问题。所以,很可能有一种方法可以获得 仅使用静态调用的活动。我花了很多时间挖掘 通过grepcode.com上的Android资源,我找到了我的样子 寻找。有一个名为ActivityThread的类。这堂课有 访问所有活动,更好的是,有一个静态方法 获取当前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是我们正在寻找的。您可能想要添加一些额外的检查。

Blog Post

答案 4 :(得分:33)

知道 ActivityManager 管理活动,因此我们可以从 ActivityManager 获取信息。我们通过

获取当前前台运行的Activity
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

更新2018/10/03
getRunningTasks()已弃用。请参阅以下解决方案。

此方法在API级别21中已弃用。 从Build.VERSION_CODES.LOLLIPOP开始,此方法不再适用于第三方应用程序:引入以文档为中心的最新版本意味着它可以将人员信息泄露给调用者。为了向后兼容,它仍将返回其数据的一小部分:至少是调用者自己的任务,以及可能已知不敏感的其他一些任务,如home。

答案 5 :(得分:5)

getCurrentActivity()也在ReactContextBaseJavaModule中 (由于这个问题最初被问到,很多Android应用程序也有ReactNative组件 - 混合应用程序。)

ReactNative中的类ReactContext具有整个逻辑集来维护在getCurrentActivity()中返回的mCurrentActivity。

注意:我希望getCurrentActivity()在Android Application类中实现。

答案 6 :(得分:3)

我找不到我们团队满意的解决方案,所以我们推出了自己的解决方案。我们使用ActivityLifecycleCallbacks来跟踪当前活动,然后通过服务公开它。更多详情:https://stackoverflow.com/a/38650587/10793

答案 7 :(得分:1)

我在Kotlin中进行了跟踪

  1. 创建应用程序类
  2. 按如下所述编辑应用程序类

    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
        }
    }
    
     }
    
  3. 创建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
    }
    
    }
    
  4. 您现在可以通过调用以下命令在任何类中使用它:FTApplication.currentActivity()

答案 8 :(得分:0)

我个人是按照“ 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实例;我将在所有其他活动的BaseActivity范围内对其进行初始化,该活动具有私有RealmHelper实例。 有关REALM的更多信息,请参见:REALM INFO LINK 例如,我的“ RealmHelper”类中有一个静态的“ RealmHelper”实例,该实例在我的应用程序“ onCreate”中实例化。我有一个同步服务,其中创建了新的“ RealmHelper”,因为Realm是“线程链接的”,并且Realm实例不能在其他线程中工作。 因此,为了遵循Realm文档“您需要关闭所有打开的Realm实例以避免系统资源泄漏”,为完成该任务,我使用了“ Application.ActivityLifecycleCallbacks”,您可以看到。

  • 最后,当我完成对应用程序的同步时,我将触发一个接收器,然后在同步结束时它将调用“ IEndSyncCallback”“ onEndSync”方法,在该方法中,我是否查看特定的Activity类我的ActivityBackStack列表,因为如果我已经在应用程序中传递了这一点,则需要执行一些操作。

仅此而已,希望对您有所帮助。见你:)

答案 9 :(得分:0)

为了向后兼容:

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;
}

答案 10 :(得分:0)

您可以使用此 Class 进行灵活的生命周期处理

用法:

    //Initialization
    val lifeCycleHandler = ActivityLifeCycleHandler<Activity>()

    //Detect only a specific type of activities
    val lifeCycleHandler = ActivityLifeCycleHandler<MainActivity>()

    //Get current activity
    val instance = lifeCycleHandler.currentReference

    //Get current activity state
    val state = lifeCycleHandler.currentState

    //Use listeners
    lifeCycleHandler.addStateChangeListener { newState ->
        //TODO: handle new state
    }

    lifeCycleHandler.addSpecificStateChangeListener(ActivityLifeCycleHandler.ActivityState.STARTED) {
        //TODO: handle new state
    }

    //Removable listeners
    val listener = { newState: Int ->

    }

    lifeCycleHandler.addStateChangeListener(listener)
    lifeCycleHandler.removeStateChageListener(listener)


    //Start listening
    App.app.registerActivityLifecycleCallbacks(lifeCycleHandler)

    //Stop listening
    lifeCycleHandler.releaseListeners()
    App.app.unregisterActivityLifecycleCallbacks(lifeCycleHandler)

答案 11 :(得分:-1)

waqas716 的答案很好。我为特定案例创建了一个解决方法,需要更少的代码和维护。

我找到了一个具体的工作,通过静态方法从我怀疑在前台的活动中获取视图。 您可以遍历所有活动并检查您是否希望或从 martin的答案中获取活动名称

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"));
}

答案 12 :(得分:-2)

我不喜欢任何其他答案。 ActivityManager不用于获取当前活动。超级分类和依赖onDestroy也很脆弱,而不是最好的设计。

老实说,到目前为止我提出的最好的方法就是在我的应用程序中维护一个枚举,它在创建活动时被设置。

另一个建议可能是尽可能避免使用多个活动。这可以通过使用片段或在我的偏好自定义视图中完成。

答案 13 :(得分:-3)

一个相当简单的解决方案是创建一个单例管理器类,您可以在其中存储对一个或多个活动的引用,或者您希望在整个应用程序中访问的任何其他内容。

在主要活动的onCreate中调用UberManager.getInstance().setMainActivity( activity );

在应用中的任意位置拨打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;
    }
}

答案 14 :(得分:-7)

我好像已经晚了三年但是无论如何我都会回答它,以防有人发现这个就像我一样。

我通过简单地使用它来解决这个问题:

    if (getIntent().toString().contains("MainActivity")) {
        // Do stuff if the current activity is MainActivity
    }

请注意,“getIntent()。toString()”包含许多其他文本,例如您的包名称以及您的活动的任何意图过滤器。从技术上讲,我们正在检查当前的意图,而不是活动,但结果是一样的。只需使用例如Log.d(“test”,getIntent()。toString());如果你想看到所有的文字。这个解决方案有点hacky,但它在代码中更清晰,功能也相同。