1

I have a special navigation in my application and i'm wondering how can I set it properly.

An activity H is the homescreen of my application. From this activity, we can launch activities A, B, C, and D. From activity A we can launch A' that launch A'', from activity B we can launch B', that launch B'', etc.

The problem is that from ANY activity, we can go to the activity H, A, B, C or D. But, when the user launch A->A'->A''->C, and then go back on A, he has to be redirected to A''. Moreover, still with this example, if the user press back on A'', he has to be redirected to A' and not to C. If he press back again he has to be redirected to A, and back again should redirect him to the H (home screen) activity, not to C !

Finally, when the user press back from H, and only at this moment, the application (and all tasks if the solution choosen is to create separated tasks) should shutdown.

Other example : H -> A -> B -> H -> back -> end of application

How can I achieve this ? I have thinked to use task like that :

<!-- A-->
<activity
    android:name=".A"
    android:excludeFromRecents="true"
    android:taskAffinity=".A"
    android:label="@string/my_A_label">
</activity>
<activity
    android:name=".A'"
    android:taskAffinity=".A"
    android:label="@string/my_A'_label">
</activity>
<activity
    android:name=".A''"
    android:taskAffinity=".A"
    android:label="@string/my_A''_label">
</activity>


<!-- B-->
<activity
    android:name=".B"
    android:excludeFromRecents="true"
    android:taskAffinity=".B"
    android:label="@string/my_B_label">
</activity>
<activity
    android:name=".B'"
    android:taskAffinity=".B"
    android:label="@string/my_B'_label">
</activity>
<activity
    android:name=".B''"
    android:taskAffinity=".B"
    android:label="@string/my_B''_label">
</activity>

...

As you can see, I have created tasks for each main page : A, B, C, D. I don't know if it's the good thing to do because, for example, with task, the user can see all theses activities on long press on his home button with the "last task" option, and I don't want have this behaviour. For that, activities A, B, C, D (root screen of each task) have the attribute android:excludeFromRecents="true". But now, another problem : when the user click on his home button, and go back to my application, he go back to home screen, not to the last activity launched...

Moreover, my second example is not respected.

Have you an idea to resolve all these problems ?

P.S : Please don't tell me to change my navigation system :-)

EDIT : here a flow chart that represents the back comportment needed. This comportment seems to be normal. What is differring in my case doesn't appear on this chart. Indeed, only back button is represented. Each context - represented by a different color - can switch to another context, without override the back comportment described here.

back comportment

EDIT2 : Thanks to advices of David Wasser, I have implemented two classes that exactly do the comportment that I have described, without using of android tasks. Thanks to JoxTraex for his help too :-) Here what I've done : my activities A,B,C,D extend RootActivity, the other except H extend CustomNavigationActivity.

RootActivity :

import android.content.Intent;

public abstract class RootActivity extends CustomNavigationActivity{

@Override
public void onBackPressed(){

    Intent intent = new Intent(this, HomeScreen.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);

}

}

CustomNavigationActivity :

import android.content.Intent;

public abstract class CustomNavigationActivity extends Activity{

private int actualRequestCode;
private int menuRequestCode = -1;

@Override
protected void onResume(){

    if (getIntent().hasExtra("childLaunched")){

        Intent intent = new Intent(this, (Class<?>) getIntent().getExtras().get("childLaunched"));
        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(intent);

    }

    super.onResume();       

}

@Override
public void startActivity (Intent intent) {

    this.startActivityForResult(intent, 0);

}

@Override
public void startActivityForResult(Intent intent, int requestCode){

    Class<?> targetClass = null;
    this.actualRequestCode = requestCode;

    if (this.actualRequestCode == this.menuRequestCode){
        this.menuRequestCode -= 1;
    }

    try {
        if (intent.getComponent() != null){
            targetClass = Class.forName(intent.getComponent().getClassName());
        }
    }
    catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    if (targetClass == null){
        super.startActivityForResult(intent, this.actualRequestCode);
    }
    else if (!targetClass.equals(Menu.class)){
        getIntent().putExtra("childLaunched", targetClass);
        super.startActivityForResult(intent, this.actualRequestCode);
    }
    else{
        super.startActivityForResult(intent, this.menuRequestCode);     
    }

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){

    if (requestCode == this.actualRequestCode){
        getIntent().removeExtra("childLaunched");
    }

}

}
Sébastien BATEZAT
  • 2,353
  • 26
  • 42
  • 1
    Well I don't see why you just can't make the ONLY entrance to your app at H. Whenever the app launches, it will always be at H. Leaving the requirement for home always being root solved. However can you explain your data and reason for such a flow. Perhaps there is a better way. For instance using the Actions in an intent for recognizing states. Also using the extras to change stuff as necessary, removing the need for multiple activities. Also you could change the activities layout as well.. so many different options. There's ever one way to handle it.. so explore for efficiecy. @sebastien – JoxTraex Aug 30 '12 at 01:52

3 Answers3

1

You definitely do not want different tasks for this. It will completely mess up your navigation if the user leaves the app (press HOME, answer a call, etc.) and wants to come back. You can only use separate tasks if you have a unique icon and/or name for the activity that is at the root of each task and if the tasks can all run in parallel. Only then will you not confuse the user. It seems that you don't want want.

Have a look at my answer to Activities Stack Issue

It isn't exactly what you want but you might get some ideas from this answer. If you still have questions after looking at this just add comments and I can help you more.

Community
  • 1
  • 1
David Wasser
  • 93,459
  • 16
  • 209
  • 274
0

Don't control it this way. Just use the control of Intents, it is far more straight forward. By doing it this way, you can prevent those dangling Activities that would be out of order.

Also when labeling your Activities DO NOT label them all with the ACTION_MAIN

refer to the documentation to find out why.

A -> B -> C

A -> B

Intent intent = new Intent((context), MyClassB.class);

B -> C

Intent intent = new Intent((context), MyClassC.class);

C -> A

Intent intent = new Intent((context), MyClassA.class);

But to handle this properly YOU HAVE TO have a good idea of how you want the flow to be. A flow chart would probably benefit you and or the explanation of your current problem. And if I may say, your current implementation/flow is a mess. I'd suggest using the aforementioned flow chart to clean up this idea.

Also if you want only ONE Activity to be your main root then your Main Activity should have the IntentFilter of ACTION_MAIN the others should NOT.

JoxTraex
  • 13,423
  • 6
  • 32
  • 45
  • Can you give me some sample code for example ? I don't know how achieve that with startActivity() and startActivityForResult(). For me, it's impossible without manage each case (and this is ugly, no ?) Moreover, for the moment, I have never used the ACTION_MAIN label in an other activity that my activity H (home screen). – Sébastien BATEZAT Aug 29 '12 at 08:07
  • Its not a label, its an intentFilter. @Sebastien – JoxTraex Aug 29 '12 at 08:16
  • Yes, for sure, my mistake. I have never used an intent filter for other activity that my home activity (H) (intent filter with CATEGORY_LAUNCHER and ACTION_MAIN). – Sébastien BATEZAT Aug 29 '12 at 08:19
  • Then every time you launch your application H should be and IS the root of your application. Then what is your specific problem? @Sebastien Please create a flow chart of your application and **HIGHLIGHT** the problem area. – JoxTraex Aug 29 '12 at 08:21
  • Just edited with a chart. I hope you will better understand my problem :-) @JoxTraex – Sébastien BATEZAT Aug 29 '12 at 08:55
0

you can prompt the activity to run another activity by startActivity(new Intent(MainActivity.this, MenuActivity.class));

Malek Hijazi
  • 4,112
  • 1
  • 26
  • 31