10

what is the better way to check if the activity is still in the stack in order to call it back ?

Intent i = new Intent(getApplicationContext(),MyClass.class);
startActivity(i);
leonidas79
  • 437
  • 2
  • 7
  • 19
  • 2
    Why care? That's up to Android. – m0skit0 Dec 20 '12 at 11:04
  • see this post http://stackoverflow.com/questions/5975811/how-to-check-if-an-activity-is-the-last-one-in-the-activity-stack-for-an-applica/6242122#6242122 – ρяσѕρєя K Dec 20 '12 at 11:04
  • cos i have an activity who needs params in order to retrieve data from and xml file , so i want call it back from the stack to avoid passing params and gettinig data from the file cos it's gonna be painfull for the user to see everytime the ProgressDialog. – leonidas79 Dec 20 '12 at 11:06

3 Answers3

6

I am surprised how unpopular this (kind of) question(s) is.

Let me start from the solution first:
Since ActivityManager.getRunningTasks is deprecated since API 21,
We have to find another way to get what activities are in the backstack. And I realized that we can actually implement our own "stack"!

I declared an ArrayList in MyOwnApplication:

private ArrayList<Class> runningActivities = new ArrayList<>();

And added public methods to access and modify this list:

public void addThisActivityToRunningActivityies (Class cls) {
    if (!runningActivities.contains(cls)) runningActivities.add(cls);
}

public void removeThisActivityFromRunningActivities (Class cls) {
    if (runningActivities.contains(cls)) runningActivities.remove(cls);
}

public boolean isActivityInBackStack (Class cls) {
    return runningActivities.contains(cls);
}

In a BaseActivity where all activities extend it:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ((MyOwnApplication)getApplication()).addThisActivityToRunningActivityies(this.getClass());
    }

@Override
protected void onDestroy() {
    super.onDestroy();
    ((MyOwnApplication)getApplication()).removeThisActivityFromRunningActivities(this.getClass());
}

And then you can easily use isActivityInBackStack to check.

WHY IS THIS NECESSARY?

Yes, of course, most cases can be done by using Intent Flags and proper navigation.
But there is such a use case, which I think should be common, that I don't find a solution simply by using intent flags.

Suppose I have an application that has a navigation drawer in almost every activity.
I navigate from MainActivity to ActivityA, and then created ChildActivityB from ActivityA. Please note that ActivityA is not parent of ChildActivityB since ChildActivityB can be opened from other activities such as notification.

Note that, ChildActivityB also has a drawer. I can navigate to ActivityA through drawer, instead of pressing up or back button. Now, imagine you loop through such process: Activity A -> ChildActivity B -> Drawer -> Activity A -> ChildActivityB -> Drawer -> Activity A ..... Infinite activities will be created in the backstack.
To fix such behavior, we need to use Intent Flags:

(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP);

So far so good. However, I have custom activity transition animations by using overridePendingTransition(). I noticed that if I put the above intent flags together with overridePendingTransition(), there will be a glitch in animation because the activity is destroyed at the middle of the animation, due to the flag Intent.FLAG_ACTIVITY_CLEAR_TOP.

Now, if I am able to detect whether ActivityA is in the backstack or not, the behavior will be perfect:

private void navigateToDrawerItems(Class cls) {
    drawerLayout.closeDrawer(GravityCompat.END);
    Intent intent = new Intent(this, cls);
    if (((MyOwnApplication)getApplication()).isActivityInBackStack(cls)) {
        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
    } else {
        startActivity(intent);
        overridePendingTransition(R.anim.slide_right_in, R.anim.slide_left_out);
    }
}
Sira Lam
  • 5,179
  • 3
  • 34
  • 68
  • +1 for mentioning the navigation use case. I will add that while this is a valid use case for navigation drawer, it's even more important for Tab Bar navigation (aka BottomNavigationView). Android has no FLAG_ACTIVITY_REORDER_TO_FRONT for fragment backstack. So if you want to easily keep state while switching between tabs AND not run out of memory, using activity tabs instead of fragment tabs is the only way. – flopshot Feb 08 '18 at 19:21
  • 1
    This stack will contain only the top-most activity after process death (low memory condition) and is therefore unreliable in production code. – EpicPandaForce Feb 03 '20 at 11:15
  • Revisiting after 2 and a half year, I now understand why this kind of question is unpopular. It is because the example I gave above is actually not a good UX. In that example, child B shouldn't be allowed to have a drawer. It should instead can just be closed, something like a pop-up activity (the concept of modal in iOS). If you have the same UX I mentioned, try to persuade your designer. – Sira Lam Feb 04 '20 at 02:12
  • But this doesn't deal with multiple instances. Say A -> B -> C -> A -> C ... How can I distinguish different instances? – LXJ Apr 08 '21 at 11:25
0

You can toggle global variable as indicator inside onCreate() and onDestory() of specific class, OR inside onActivityCreated() and onActivityDestroyed() of ActivityLifecycleCallbacks.

e.g.:

  registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

      @Override
      public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
          if (activity instanceof YourActivity) {
              myGlobalData.setActExist(true);
          } 
      }

      @Override
      public void onActivityDestroyed(Activity activity) {
          if (activity instanceof YourActivity) {
              myGlobalData.setActExist(false);
          }
      }
  });
林果皞
  • 7,539
  • 3
  • 55
  • 70
-1

Look at the ActivityManager API

To get an instance of the ActivityManager use this code:

ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
ben75
  • 29,217
  • 10
  • 88
  • 134
  • 14
    It would be great to have more details on how exactly should I use ActivityManager to check if the activity is on the stack. Just "read documentation of this class" is not good enough IMO. – Tapemaster Sep 09 '14 at 13:39
  • 1
    He was referring to ActivityManager.getRunningTasks, but it's been deprecated in lollipop. – grebulon Feb 07 '16 at 09:18