如何在android中获得当前前景活动上下文?

每当我的广播执行时,我想显示对前景活动的警报。

381149 次浏览

更新3:已经为此添加了官方api,请改用ActivityLifecycleCallbacks

知道ActivityManager管理活动,所以我们可以从ActivityManager获取信息。我们得到当前的前景运行活动

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
< p >更新2018/10/03 < br > getRunningTasks()已弃用。

.

. 此方法在API级别21中已弃用。 从Build.VERSION_CODES开始。LOLLIPOP,这种方法不再适用于第三方应用程序:以文档为中心的最近记录的引入意味着它可能会向调用者泄露人员信息。为了向后兼容,它仍然会返回它的数据的一个小子集:至少是调用者自己的任务,可能还有一些已知不敏感的其他任务,比如home

< a href = " https://stackoverflow.com/users/870218/waqas716 " > waqas716 < / >的答案是好的。我针对需要更少代码和维护的特定情况创建了一个变通方案。

我找到了一个特定的工作,通过一个静态方法从我怀疑是在前景的活动中获取一个视图。 您可以遍历所有活动并检查是否希望或从马丁的 answer

中获得活动名称
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

然后我检查视图是否为空,并通过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"));
}

(注意:在API 14中添加了一个官方API:参见此答案https://stackoverflow.com/a/29786451/119733)

不要使用以前的(waqas716)答案。

由于对活动的静态引用,您将有内存泄漏问题。有关更多详细信息,请参阅下面的链接http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html

为了避免这种情况,您应该管理活动引用。 在manifest文件中添加应用程序的名称:

<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();

我在@gezdy的答案上方展开。

在每个Activities中,我们不必通过手动编码将自身“注册”到Application中,而是可以使用下面的API,从第14级开始,帮助我们用更少的手动编码实现类似的目的。

public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

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

Application.ActivityLifecycleCallbacks中,你可以得到哪个Activity“附加”到或“分离”到这个Application

但是,这种技术只在API级别14之后才可用。

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

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

另一个建议可能是尽量避免使用多个活动。这既可以使用片段,也可以在我喜欢的自定义视图中完成。

我迟到了3年,但我还是会接的,以防有人像我一样发现这个。

我解决这个问题的方法很简单:

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

注意"getIntent(). tostring()"包含了一堆其他文本,比如你的包名和你的活动的任何意图过滤器。从技术上讲,我们检查的是当前的意图,而不是活动,但结果是一样的。就用Log吧。d(“测试”,getIntent () .toString ());如果你想看所有的文字。这个解决方案有点俗气,但它在你的代码中要干净得多,功能是相同的。

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

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

在应用程序的任何地方调用UberManager.getInstance().getMainActivity();来检索它。(我使用这个能够使用吐司从一个非UI线程。)

当你的应用程序被销毁时,确保你添加了对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;
}
}

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

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

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

注:我希望getCurrentActivity()在Android应用程序类中实现。

我在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. Create the ActivityLifecycleCallbacks class

    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. you can now use it in any class by calling the following: FTApplication.currentActivity()

就我个人而言,我是按照“Cheok Yan Cheng”说的去做的,但我使用了一个“列表”来对我所有的活动进行“备份”。

如果你想检查哪个是当前活动,你只需要得到列表中的最后一个活动类。

创建一个扩展“application”的应用程序,这样做:

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()     }
}


}

在我的例子中,我使用了“应用程序”。ActivityLifecycleCallbacks”:

  • 绑定/解绑定Merlin实例(用于在应用程序丢失或获得连接时获取事件,例如当你关闭移动数据或当你打开它时)。它在“OnConnectivityChanged”意图动作被禁用后很有用。 有关MERLIN的更多信息,请参见:梅林信息链接

  • 当应用程序关闭时关闭我的最后一个域实例;我将在一个BaseActivity中初始化它,它是从所有其他活动扩展而来的,并且它有一个私有的RealmHelper实例。 有关REALM的更多信息,请参阅:领域信息链接 例如,我有一个静态的“RealmHelper”实例在我的“RealmHelper”类是实例化在我的应用程序“onCreate”。我有一个同步服务,在其中我创建了我新的“RealmHelper”,因为领域是“线程链接”和领域实例不能在不同的线程内工作。 所以为了遵循领域文档“你需要关闭所有打开的领域实例以避免系统资源泄漏”,我使用了“应用程序”来完成这件事。ActivityLifecycleCallbacks"就像你看到的那样。李< / p > < / >

  • 最后,当我完成同步我的应用程序时,我有一个接收器被触发,然后当同步结束时,它会调用“IEndSyncCallback”“onEndSync”方法,其中我看看我是否在我的actitiesbackstack列表中有一个特定的活动类,因为我需要更新视图上的数据,如果同步更新了它们,我可能需要在应用程序同步后做其他操作。

以上就是全部内容,希望对大家有所帮助。见u:)

为了向后兼容:

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

你可以使用这个来进行灵活的生命周期处理

用法:

    //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)

通过使用这部分代码,您可以检测应用程序何时进入后台/前台,并访问当前活动名称和上下文。

我的答案基于这篇文章:Android:如何检测当应用程序进入后台/前台

首先,创建一个扩展android.app.Application并实现ActivityLifecycleCallbacks接口的类。在Application.onCreate()中,注册回调。

public class App extends Application implements ActivityLifecycleCallbacks
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}

在Manifest中注册“App”类,如下所示:

<application
android:name=".App"

这就是ActivityLifecycleCallbacks接口的样子,

public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
因此,当你的任何活动(你创建或包含在你的库中的活动)通过上述任何生命周期方法时,这些回调将被调用。 当应用程序在前台时,至少有一个Activity处于启动状态,当应用程序在后台时,将没有Activity处于启动状态。 在" App "类中声明如下2个变量
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;

activityReferences将保持启动状态下活动的计数。isActivityChangingConfigurations是一个标志,用于指示当前Activity是否正在经历配置更改,如方向切换。 使用下面的代码,你可以检测App是否出现在前台

@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}

你可以在这个方法中像这样访问context:

activity.getBaseContext()

这是如何检测应用程序是否进入后台。

Override
public void onActivityStopped(Activity activity) {


isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}

现在您可以访问当前的前台活动名称和上下文。

使用is操作符或其否定形式!is执行运行时检查,以确定对象是否符合给定类型:

if (this !is OneActivity) {
// do something
} else if (this !is TwoActivity) {
// do something 2
}

在你的应用程序中创建一个类名ActivityManager (java)

public class ActivityManager implements Application.ActivityLifecycleCallbacks {


private Activity activity;




public ActivityManager(App myApplication) {
myApplication.registerActivityLifecycleCallbacks(this);
}


public Activity getActivity(){
return activity;
}
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
this. activity = activity;


}


@Override
public void onActivityStarted(@NonNull Activity activity) {
this. activity = activity;
}


@Override
public void onActivityResumed(@NonNull Activity activity) {
this. activity = activity;


}


@Override
public void onActivityPaused(@NonNull Activity activity) {


}


@Override
public void onActivityStopped(@NonNull Activity activity) {


}


@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {


}


@Override
public void onActivityDestroyed(@NonNull Activity activity) {


}
}

然后在应用程序(kotlin)中初始化它

class App : Application() {


override fun onCreate() {
     

appOpenManager =  AppOpenManager(this);
}
companion object {
lateinit var appOpenManager: AppOpenManager
}
}

然后用like

App.activityManager.getActivity ()