-2

I have a system which has several Activity, Activity X, Activity A, Activity B, and Activity Y. Activity X consist of list of A. If we click on A, it will go to Activity A. Activity A consist of list of B. If we click on B, it will go to Activity B. Activity B will also consist of list of B. So, if we click B on Activity B, it will go to Activity B. It is possible to end up the stack like this: X -> A -> B -> B -> B -> B -> B. According to proper navigation by Android, if we click Up on Activity B, it should go to Activity A, no matter how deep the stack is. So, every B on the previous stack should end up on A. Up until now, it's simple. I just need to set the parent class of Activity B as Activity A.

The problem is I can go to Activity B from Activity Y. If I open the Activity B from Activity Y, this Activity B is not always know how to open Activity A because the parent of B can be another B or A. B only know his parent. The problem is how to detect that Activity A is reachable automatically without creating a new instance from Activity B? This way, I can make my code like the following on Activity B.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if (canGoUpToActivityA()) { // this means this Activity B is opened from Activity A directly (A -> B) or indirectly (A -> B -> ... -> B), not from Activity Y
                NavUtils.navigateUpFromSameTask(this);
                return true;
            } else {
                Intent intent;

                if (TYPE_B.equals(mParent.getType())) {
                   intent = new Intent(this, ActivityB.class);
                } else {
                   intent = new Intent(this, ActivityA.class);
                }

                intent.putExtra(EXTRA_ITEM, mParent)
                startActivity(intent);                    

                return true;
            }
        default:
            return super.onOptionsItemSelected(item);
    }
}

EDIT

If anybody down voting me because they think the solution is as simple as singleTop to Activity A, that's mean you guys don't understand my problem. See the last sentence of my first paragraph. I don't have any problem with going up from Activity B to Activity A, no matter how deep it is if Activity B is opened from Activity A.

Without the above onOptionsItemSelected, I can go up to Activity A from Activity B if Activity B is opened from Activity A directly (A -> B) or indirectly (A -> B -> ... -> B). This is not my problem.

The problem comes when I opened Activity B from Activity Y. I can't just go back to Activity A because Activity A rely on information from Activity X. If I open Activity B from Activity Y, then I go up, I should go to the parent of Activity B, where it can be A or another B.

The above code without canGoUpToActivityA() part will solve my problem. With that code, when I open Activity B from Activity Y, then going up should always go to the parent of B. That's already correct (B only know its parent, which can be not A).

But, when I open Activity B from Activity A, then I go up, it will launch the parent of Activity B. If I open Activity B from Activity A directly (A -> B), it's is indeed what I want. But, when I open Activity B from another Activity B (A-> B -> ... -> B), that's the problem. Because I should go up to Activity A, not the parent of Activity B which can be another Activity B.

Sam
  • 351
  • 1
  • 2
  • 15
  • Why not this https://stackoverflow.com/a/13383025/2700586? – Mani Aug 02 '17 at 01:42
  • I got a feeling you haven't read about launch modes: https://developer.android.com/guide/topics/manifest/activity-element.html#lmode – Marcin Orlowski Aug 02 '17 at 01:43
  • @MarcinOrlowski I've put `singleTop` for `Activity A` – Sam Aug 02 '17 at 01:44
  • That should resolve your issue of having Activity B with another Activity B as a parent then. – Allan W Aug 02 '17 at 01:46
  • @Mani It's different case – Sam Aug 02 '17 at 01:49
  • @AllanW, I never say I have a problem with that. The problem comes when I open `Activity B` from `Activity Y`, where in this case `Activity B` cannot open `Activity A` directly since `Activity B` don't know how to open `Activity A`. `Activity B` is also don't come from `Activity A`, but `Activity Y`. – Sam Aug 02 '17 at 01:51
  • You mentioned not knowing about the parent in the question and gave that as an example. If you always want `activity B` to launch `activity A` when pressing back, why not just launch an intent to `activity A`? It won't matter what's in the back stack then. And you can use the links above to allow activities that are in the backstack to be moved to the top rather than recreated and positioned twice. – Allan W Aug 02 '17 at 01:58
  • @AllanW Yes, `Activity B` only know its own parent. If all the parent of `B` is always `A`, i can open `Activity A` with intent. But, the problem is the parent of `B` can be `A` or another `B`. I need to have conditional check for this one to open `Activity A` if the parent is `A` or to open `Activity B` if the parent is `B`. I've solved this one with the above code without `canGoUpToActivityA()` part. But, that means from `Activity B`, I always go to the parent of `B`, where it can be another `B`. If I open it from `Activity Y`, that's what I want. But, if I open it from `Activity A` it's not – Sam Aug 02 '17 at 02:06

1 Answers1

0

I'm still not clear on what exactly you want, so I'll break this up into snippets:

If you want to launch a parent of Activity B and ensure that it isn't "launching itself", you can use the singleTop flag as noted by others to ensure that only one instance of B is ever on the top. You mentioned you don't have an issue with that, but you've listed that as an example, so just keep that in mind.

You've also mentioned that you check if the parent is A before launching Activity A. If all you want to do is actually launch the previous activity in the stack, there is no need for an Intent. Just finish your activity and it will exit the stack, showing the previous activity.

If you have a set activity that you should launch when going back, you can simply launch it with an intent. At this point, it doesn't matter what the previous activity is, because you are explicitly starting an activity for a given class. Again, you may look at the FLAG_ACTIVITY_REORDER_TO_FRONT flag to ensure that an existing activity is not recreated.

Lastly, if you have some complex logic that requires you to know the full stack history, you can always pass data through your bundle. A simple example is an arraylist of the simple class name so you know everything in the current task.


Edit: Since you've also added that you depend on information from previous classes, I take it that you need more than just the class name.

Note that you can always pass data through the bundles so that they are retained through all subsequent activities. You can also pass all the current data by calling putExtras.

And if your entire flow is geared towards going to a child and then passing data back to a parent, consider using [startActivityForResult](https://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)). That way, you can set result codes and data and finish your activity to directly pass information to the previous activity, without launching a new intent in a forward flow manner.

Allan W
  • 2,791
  • 4
  • 23
  • 41
  • I ended up with the solution in your last paragraph. – Sam Aug 02 '17 at 04:16
  • @Sam I have updated my answer since you mentioned that activities actually depend on data in other activities. This implies you'll need to know more than just which activities are in the stack. – Allan W Aug 02 '17 at 05:49