开发者

Android: how do I check if activity is running?

Is there any simple way of determining whether or not a certain a开发者_运维技巧ctivity is active? I want to do certain things depending on which activity is active. eg:

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else


You can use a static variable within the activity.

class MyActivity extends Activity {
     static boolean active = false;

      @Override
      public void onStart() {
         super.onStart();
         active = true;
      } 

      @Override
      public void onStop() {
         super.onStop();
         active = false;
      }
}

The only gotcha is that if you use it in two activities that link to each other then onStop on the first is sometimes called after onStart in second. So both might be true briefly.

Depending on what you are trying to do (update the current activity from a service?). You could just register a static listener in the service in your activity onStart method then the correct listener will be available when your service wants to update the UI.


I realize this issue is quite old, but I think it's still worth sharing my solution as it might be useful to others.

This solution wasn't available before Android Architecture Components were released.

Activity is at least partially visible

getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)

Activity is in the foreground

getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)


I think more clear like that:

  public boolean isRunning(Context ctx) {
        ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (RunningTaskInfo task : tasks) {
            if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName())) 
                return true;                                  
        }

        return false;
    }


An option without using any auxiliar variable is:

activity.getWindow().getDecorView().getRootView().isShown()

where activity is f.e.: this or getActivity().

The value returned by this expression changes in onStart() / onStop(), which are the events that start / stop showing the layout of the activity on the phone.


I used MyActivity.class and getCanonicalName method and I got answer.

protected Boolean isActivityRunning(Class activityClass)
{
        ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (ActivityManager.RunningTaskInfo task : tasks) {
            if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName()))
                return true;
        }

        return false;
}


Far better way than using a static variable and following OOP

Shared Preferences can be used to share variables with other activities and services from one application

    public class example extends Activity {

    @Override
    protected void onStart() {
        super.onStart();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", true);
        ed.commit();
    }

    @Override
    protected void onStop() {
        super.onStop();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", false);
        ed.commit();

    }
}

Use shared preferences. It has the most reliable state information, less application switch/destroy issues, saves us to ask for yet another permission and it gives us more control to decide when our activity is actually the topmost. see details here abd here also


if(!activity.isFinishing() && !activity.isDestroyed())

From the official docs:

Activity#isFinishing()

Check to see whether this activity is in the process of finishing, either because you called finish() on it or someone else has requested that it finished. This is often used in onPause() to determine whether the activity is simply pausing or completely finishing.

Activity#isDestroyed()

Returns true if the final onDestroy() call has been made on the Activity, so this instance is now dead.


This is code for checking whether a particular service is running. I'm fairly sure it can work for an activity too as long as you change getRunningServices with getRunningAppProcesses() or getRunningTasks(). Have a look here http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses()

Change Constants.PACKAGE and Constants.BACKGROUND_SERVICE_CLASS accordingly

    public static boolean isServiceRunning(Context context) {

    Log.i(TAG, "Checking if service is running");

    ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

    boolean isServiceFound = false;

    for (int i = 0; i < services.size(); i++) {

        if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){

            if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
                isServiceFound = true;
            }
        }
    }

    Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");

    return isServiceFound;

}


thanks kkudi! I was able to adapt your answer to work for an activity... here's what worked in my app..

public boolean isServiceRunning() { 

ActivityManager activityManager = (ActivityManager)Monitor.this.getSystemService (Context.ACTIVITY_SERVICE); 
    List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE); 
    isServiceFound = false; 
    for (int i = 0; i < services.size(); i++) { 
        if (services.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.lyo.AutoMessage/com.lyo.AutoMessage.TextLogList}")) {
            isServiceFound = true;
        }
    } 
    return isServiceFound; 
} 

this example will give you a true or false if the topActivity matches what the user is doing. So if the activity your checking for is not being displayed (i.e. is onPause) then you won't get a match. Also, to do this you need to add the permission to your manifest..

<uses-permission  android:name="android.permission.GET_TASKS"/>

I hope this was helpful!


There is a much easier way than everything above and this approach does not require the use of android.permission.GET_TASKS in the manifest, or have the issue of race conditions or memory leaks pointed out in the accepted answer.

  1. Make a STATIC variable in the main Activity. Static allows other activities to receive the data from another activity. onPause() set this variable false, onResume and onCreate() set this variable true.

    private static boolean mainActivityIsOpen;
    
  2. Assign getters and setters of this variable.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
    
  3. And then from another activity or Service

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }
    


I think the accepted answer is an awful way of handling this.

I don't know what the use case is, but please consider a protected method in the base class

@protected
void doSomething() {
}

and override it in the derived class.

When the event occurs, just call this method in the base class. The correct 'active' class will handle it then. The class itself can then check if it is not Paused().

Better yet, use an event bus like GreenRobot's, Square's, but that one is deprecated and suggests using RxJava


Have you tried..

    if (getActivity() instanceof NameOfYourActivity){
        //Do something
    }


ActivityLifecycleCallbacks is a great way of keeping track of all the activities in App:

public class BaseActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

private ActivityState homeState, contentState;

@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.CREATED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.CREATED;
    }
}

@Override
public void onActivityStarted(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STARTED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STARTED;
    }
}

@Override
public void onActivityResumed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.RESUMED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.RESUMED;
    }
}

@Override
public void onActivityPaused(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.PAUSED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.PAUSED;
    }
}

@Override
public void onActivityStopped(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STOPPED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STOPPED;
    }
}

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

@Override
public void onActivityDestroyed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.DESTROYED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.DESTROYED;
    }
}

public ActivityState getHomeState() {
    return homeState;
}

public ActivityState getContentState() {
    return contentState;
}
}

ActivityState:

public enum ActivityState {
    CREATED, STARTED, RESUMED, PAUSED, STOPPED, DESTROYED;
}

Extend the Application class and provide its reference in Android Manifest file:

import android.app.Application;

public final class BaseApplication extends Application {
private BaseActivityLifecycleCallbacks baseALC;

@Override
public void onCreate() {
    super.onCreate();
    baseALC = new BaseActivityLifecycleCallbacks();
    this.registerActivityLifecycleCallbacks(baseALC);

}

public BaseActivityLifecycleCallbacks getBaseALC() {
    return baseALC;
}
}

Ckeck anywhere from Activity for status of other activity:

private void checkAndLaunchHomeScreen() {
    Application application = getApplication();
    if (application instanceof BaseApplication) {
        BaseApplication baseApplication = (BaseApplication) application;
        if (baseApplication.getBaseALC().getHomeState() == null || baseApplication.getBaseALC().getHomeState() == ActivityState.DESTROYED) {
            //Do anything you want
        }
    }
}

https://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html


I used a check if (!a.isFinishing()) and it seems to do what i need. a is the activity instance. Is this incorrect? Why didn't anyone try this?


what about activity.isFinishing()


Not sure it is a "proper" way to "do things".
If there's no API way to resolve the (or a) question than you should think a little, maybe you're doing something wrong and read more docs instead etc.
(As I understood static variables is a commonly wrong way in android. Of cause it could work, but there definitely will be cases when it wont work[for example, in production, on million devices]).
Exactly in your case I suggest to think why do you need to know if another activity is alive?.. you can start another activity for result to get its functionality. Or you can derive the class to obtain its functionality and so on.
Best Regards.


If you are interested in the lifecycle state of the specific instance of the activity, siliconeagle's solution looks correct except that the new "active" variable should be an instance variable, rather than static.


Use an ordered broadcast. See http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html

In your activity, register a receiver in onStart, unregister in onStop. Now when for example a service needs to handle something that the activity might be able to do better, send an ordered broadcast from the service (with a default handler in the service itself). You can now respond in the activity when it is running. The service can check the result data to see if the broadcast was handled, and if not take appropriate action.


In addition to the accepted answer, if you have multiple instances of the activity, you can use a counter instead to handle multiple instances :

class MyActivity extends Activity {

     static int activeInstances = 0;

     static boolean isActive() {
        return (activeInstances > 0);
     }

      @Override
      public void onStart() {
         super.onStart();
         activeInstances++;
      } 

      @Override
      public void onStop() {
         super.onStop();
         activeInstances--;
      }
}


public static boolean isActivityActive(Activity activity) {
   if (null != activity)
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
         return !activity.isFinishing() && !activity.isDestroyed();
      else return !activity.isFinishing();
   return false;
}


Found an easy workaround with the following code

@Override 
protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { 
                // Activity is being brought to front and not being  created again, 
                // Thus finishing this activity will bring the last viewed activity to foreground
                finish(); 
            } 
    }


Use the isActivity variable to check if activity is alive or not.

private boolean activityState = true;

 @Override
protected void onDestroy() {
    super.onDestroy();
    activityState = false;
}

Then check

if(activityState){
//add your code
}


If you want to check if the activity is in the back stack just follow next steps. 1. Declared an ArrayList in your Application class [Application class is defined in your mainfest file in application tag]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. And add the following public methods to access and modify this list.

    public void addActivityToRunningActivityies (Class cls) {
    if (!runningActivities.contains(cls)) runningActivities.add(cls);
    }
    
    public void removeActivityFromRunningActivities (Class cls) {
    if (runningActivities.contains(cls)) runningActivities.remove(cls);
    }
    
    public boolean isActivityInBackStack (Class cls) {
    return runningActivities.contains(cls);
    }
    
  2. In your BaseActivity, where all activities extend it, override onCreate and onDestroy methods so you can add and remove activities from back stack as the following.

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    ((MyApplicationClass)getApplication()).addActivityToRunningActivityies
    (this.getClass());
    }
    
    @Override
    protected void onDestroy() {
    super.onDestroy();
    
    ((MyApplicationClass)getApplication()).removeActivityFromRunningActivities
    (this.getClass());
    }
    
  3. Finally if you want to check whether the activity is in the back stack or not just call this function isActivityInBackStack.

Ex: I want to check if the HomeActivityis in the back stack or not:

if (((MyApplicationClass) 
getApplication()).isActivityInBackStack(HomeActivity.class)) {
       // Activity is in the back stack
    } else {
       // Activity is not in the back stack
    }


I have used task.topActivity instead of task.baseActivity and it works fine for me.

   protected Boolean isNotificationActivityRunning() {
    ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

    for (ActivityManager.RunningTaskInfo task : tasks) {
        if (task.topActivity.getClassName().equals(NotificationsActivity.class.getCanonicalName()))
            return true;
    }

    return false;
}


I know this question is old and has a lot of varying answers, with various bonuses and drawbacks. My take on it, is why not roll your own IPC implementation.

class IPC {

    companion object {
        private val appContext : Context by lazy { /*genericApplicationContext*/ }

        fun initIPC(process: String){
            var file : File? = null
            file = File(appContext.cacheDir.absolutePath + "/$process")
            var output : OutputStream? = null
            try {
                output = FileOutputStream(file!!)
                output.write(0)
            } finally {
                output?.close()
            }
        }

        fun destroyIPC(process: String){
            var file : File? = null
            file = File(appContext.cacheDir.absolutePath + "/$process")
            file.delete()
        }

        fun checkForIPC(process: String) : Boolean {
            var file : File? = null
            file = File(appContext.cacheDir.absolutePath + "/$process")
            if(file.exists()) return true
            return false
        }
    }

}

This allows you to create the file before launching the activity, and then close out the "process/file" when you close the launched activity. This allows you to check in a background thread or current activity if your "process activity" is in the background to see if the file is still open signaling that the activity is alive. In my case I am calling an external API in succession but need to rate limit the calls, so use this to make sure only one activity is alive calling the APIs at a time.


This is what I came up with for helping keep track of different activities with their classes derived from a base 'helper' class.

protected static Dictionary<string, bool> _activityInstances = new Dictionary<string, bool>();
protected static Dictionary<string, bool> _activitiesVisible = new Dictionary<string, bool>();
        
protected override void OnStart()
{
    base.OnStart();
    _activityInstances[this.GetType().Name] = true;
}

protected override void OnDestroy()
{
    _activityInstances[this.GetType().Name] = false;
    base.OnDestroy();
}

protected override void OnResume()
{
    base.OnResume();
    _activitiesVisible[this.GetType().Name] = true;
}

protected override void OnPause()
{
    _activitiesVisible[this.GetType().Name] = false;
    base.OnPause();
}

public static bool activityIsInstanced(string type)
{
    return _activityInstances.ContainsKey(type) ? _activityInstances[type] : false;
}

public static bool activityIsVisible(string type)
{
    return _activitiesVisible.ContainsKey(type) ? _activityInstances[type] : false;
}

It is able to inherited but in order to run a test (i.e. before launching a new copy of a particular activity) you would need to call the static method with the name of the class, e.g.

    if (!SettingsEdit.activityIsInstanced("SettingsEdit"))
    {
        Intent intent = new Intent(this, typeof(SettingsEdit));
        Bundle bundle = new Bundle();
        bundle.PutString(MY_SETTING, this.someSetting);
        intent.PutExtras(bundle);
        this.StartActivityForResult(intent, 0);
    }

If it helps anyone, I thought I'd share it here.


This work if you don't have the same activity in foreground. If you open from notification don't work i made some adjustments and came with this:

public static boolean ativo = false;
public static int counter = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    counter++;
}

@Override
protected void onStart() {
    super.onStart();
    ativo = true;
}

@Override
protected void onStop() {
    super.onStop();
    if (counter==1) ativo = false;
}

@Override
protected void onDestroy() {
    counter--;
    super.onDestroy();
}

That works for me with several activitys open at the same time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜