Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restore Android back stack after app has been closed

What's the best practise to manage / restore application back stack between multiple sessions ?

Exemple of a Workflow :

  1. Activity A started (stack: A)
  2. Activity B started (stack: A B)
  3. Activity C started (stack: A B C)
  4. ...
  5. User uses a different application (let's say the GMail app) for a while
  6. ...
  7. User goes back to my application, but the back stack has been cleared by Android.

At step 7, I'd like to have Activity C resumed, and that if user presses the back button 2 times, it will go back to Activity B, and then Activity A.

[Edit] Adding details.

After step 7 above, What happens by default in Android is this :

  1. Activity A started (stack: empty, and C is added)

And I would like the user to feel like he is still using the same session:

  1. Activity C resumed (stack: A B C)
  2. User presses back button, Activity B resumed (stack: A B)
  3. User presses back button, Activity A resumed (stack: A)

What would be a good approach to this situation while avoiding memory leaks ?

[Second EDIT] I have been crafting a workaround using a commong class UIController to all activities, and a LauncherActivity to delegate the logic to the UIController.

Since I only need to rebuild the back stack when ActivityC has been started, this solution seems to work fine :

public class UIController
{
    private boolean _launched = false;

    static private final UIController __instance = new UIController();
    static public UIController getInstance() { return __instance; }

    // Enforces the Singleton Pattern by preventing external access to constructor
    private UIController() { }

    public void onActivityCreated(Activity activity) {
        if (!_launched)
        {
            if ( shouldRebuildStack() )
            {
                // Rebuild Activity stack

                // Npte : actually Android will add ActivityA and ActivityB to the stack
                // but will *NOT* create them right away. Only ActivityC will be 
                // created and resumed.
                // Since they are in the back stack, the other activities will be 
                // created by Android once needed.
                startActivity(activity, ActivityA.class);
                startActivity(activity, ActivityB.class);
                startActivity(activity, ActivityC.class);
            } else {
                // Starts default activity
                startActivity(activity, ActivityA.class);
            }

            _launched = true;
        }
    }

    public void onActivityResumed(Activity activity) {
        memorizeCurrentActivity( activity.getClass().toString() );
    }

    private void memorizeCurrentActivity( String className ) {
        // write className to preferences, disk, etc.
    }

    private boolean shouldRebuildStack() {
        String previousActivity = " [load info from file, preferences, etc.] ";
        return (previousActivity != null && previousActivity.equals("my.package.ActivityC"));
    }

    private void startActivity(Activity caller, Class newActivityClass)
    {
        Intent intent = new Intent(caller, newActivityClass);
        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        caller.startActivity( intent );
    }
}

// This is the default activity in the AndroidManifest.xml
// This prevents ActivityA from starting right away if the UIController
// wants to rebuild the stack.
public class LauncherActivity() {
    protected void onCreate(Bundle data) {
        super.onCreate(data);
        UIController.getInstance().onActivityCreated(this);
        finish();
    }
}

public class ActivityA() {
    protected void onCreate(Bundle data) {
        super.onCreate(data);
        UIController.getInstance().onActivityCreated(this);
    }
    protected void onResume() {
        super.onResume();
        UIController.getInstance().onActivityResumed(this);
    }
}

public class ActivityB() {
    // onCreate() & onResume(), same as ActivityA
}

public class ActivityC() {
    // onCreate() & onResume(), same as ActivityA
}

public class LauncherActivity() {
    protected void onCreate(Bundle data) {
        super.onCreate(data);
        UIController.getInstance().onActivityCreated(this);
        finish();
    }
}

public class ActivityA() {
    protected void onCreate(Bundle data) {
        super.onCreate(data);
        UIController.getInstance().onActivityCreated(this);
    }
    protected void onResume() {
        super.onResume();
        UIController.getInstance().onActivityResumed(this);
    }
}

public class ActivityB() {
    // same as ActivityA
}

public class ActivityC() {
    // same as ActivityA
}

If someone has a better solution, feel free to post it.

like image 340
David Avatar asked Jul 26 '11 20:07

David


1 Answers

Sounds like you should set this to true and let Android handle managing the activity stack.

android:alwaysRetainTaskState

If this attribute is set to "true" in the root activity of a task, the default behavior just described does not happen. The task retains all activities in its stack even after a long period.

like image 98
CrackerJack9 Avatar answered Sep 22 '22 15:09

CrackerJack9